diff --git a/src/pkg/runtime/arch_power64.h b/src/pkg/runtime/arch_power64.h new file mode 100644 index 0000000000..3d5b4943c7 --- /dev/null +++ b/src/pkg/runtime/arch_power64.h @@ -0,0 +1,14 @@ +// 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. + +enum { + thechar = '9', + BigEndian = 1, + CacheLineSize = 64, + RuntimeGogoBytes = 84, + PhysPageSize = 4096, + PCQuantum = 4, + Int64Align = 8 +}; + diff --git a/src/pkg/runtime/arch_power64le.h b/src/pkg/runtime/arch_power64le.h new file mode 100644 index 0000000000..d9241da98b --- /dev/null +++ b/src/pkg/runtime/arch_power64le.h @@ -0,0 +1,14 @@ +// 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. + +enum { + thechar = '9', + BigEndian = 0, + CacheLineSize = 64, + RuntimeGogoBytes = 84, + PhysPageSize = 4096, + PCQuantum = 4, + Int64Align = 8 +}; + diff --git a/src/pkg/runtime/asm_power64x.s b/src/pkg/runtime/asm_power64x.s new file mode 100644 index 0000000000..52640f407a --- /dev/null +++ b/src/pkg/runtime/asm_power64x.s @@ -0,0 +1,997 @@ +// 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. + +// +build power64 power64le + +#include "zasm_GOOS_GOARCH.h" +#include "funcdata.h" +#include "../../cmd/ld/textflag.h" + +TEXT _rt0_go(SB),NOSPLIT,$0 + // initialize essential registers + BL runtime·reginit(SB) + + SUB $24, R1 + MOVW R3, 8(R1) // argc + MOVD R4, 16(R1) // argv + + // create istack out of the given (operating system) stack. + // _cgo_init may update stackguard. + MOVD $runtime·g0(SB), g + MOVD $(-64*1024), R31 + ADD R31, R1, R3 + MOVD R3, g_stackguard(g) + MOVD R3, g_stackguard0(g) + MOVD R1, g_stackbase(g) + + // TODO: if there is a _cgo_init, call it. + // TODO: add TLS + + // set the per-goroutine and per-mach "registers" + MOVD $runtime·m0(SB), R3 + + // save m->g0 = g0 + MOVD g, m_g0(R3) + // save m0 to g0->m + MOVD R3, g_m(g) + + BL runtime·check(SB) + + // args are already prepared + BL runtime·args(SB) + BL runtime·osinit(SB) + BL runtime·hashinit(SB) + BL runtime·schedinit(SB) + + // create a new goroutine to start program + MOVD $runtime·main·f(SB), R3 // entry + MOVDU R3, -8(R1) + MOVDU R0, -8(R1) + MOVDU R0, -8(R1) + ARGSIZE(24) + BL runtime·newproc(SB) + ARGSIZE(-1) + ADD $24, R1 + + // start this M + BL runtime·mstart(SB) + + MOVD R0, 1(R0) + RETURN + +DATA runtime·main·f+0(SB)/8,$runtime·main(SB) +GLOBL runtime·main·f(SB),RODATA,$8 + +TEXT runtime·breakpoint(SB),NOSPLIT,$-8-0 + MOVD R0, 2(R0) // TODO: TD + RETURN + +TEXT runtime·asminit(SB),NOSPLIT,$-8-0 + RETURN + +TEXT runtime·reginit(SB),NOSPLIT,$-8-0 + // set R0 to zero, it's expected by the toolchain + XOR R0, R0 + // initialize essential FP registers + FMOVD $4503601774854144.0, F27 + FMOVD $0.5, F29 + FSUB F29, F29, F28 + FADD F29, F29, F30 + FADD F30, F30, F31 + RETURN + +/* + * go-routine + */ + +// void gosave(Gobuf*) +// save state in Gobuf; setjmp +TEXT runtime·gosave(SB), NOSPLIT, $-8-8 + MOVD gobuf+0(FP), R3 + MOVD R1, gobuf_sp(R3) + MOVD LR, R31 + MOVD R31, gobuf_pc(R3) + MOVD g, gobuf_g(R3) + MOVD R0, gobuf_lr(R3) + MOVD R0, gobuf_ret(R3) + MOVD R0, gobuf_ctxt(R3) + RETURN + +// void gogo(Gobuf*) +// restore state from Gobuf; longjmp +TEXT runtime·gogo(SB), NOSPLIT, $-8-8 + MOVD gobuf+0(FP), R5 + MOVD gobuf_g(R5), g // make sure g is not nil + MOVD 0(g), R4 + MOVD gobuf_sp(R5), R1 + MOVD gobuf_lr(R5), R31 + MOVD R31, LR + MOVD gobuf_ret(R5), R3 + MOVD gobuf_ctxt(R5), R11 + MOVD R0, gobuf_sp(R5) + MOVD R0, gobuf_ret(R5) + MOVD R0, gobuf_lr(R5) + MOVD R0, gobuf_ctxt(R5) + CMP R0, R0 // set condition codes for == test, needed by stack split + MOVD gobuf_pc(R5), R31 + MOVD R31, CTR + BR (CTR) + +// void mcall(void (*fn)(G*)) +// Switch to m->g0's stack, call fn(g). +// Fn must never return. It should gogo(&g->sched) +// to keep running g. +TEXT runtime·mcall(SB), NOSPLIT, $-8-8 + // Save caller state in g->sched + MOVD R1, (g_sched+gobuf_sp)(g) + MOVD LR, R31 + MOVD R31, (g_sched+gobuf_pc)(g) + MOVD R0, (g_sched+gobuf_lr)(g) + MOVD g, (g_sched+gobuf_g)(g) + + // Switch to m->g0 & its stack, call fn. + MOVD g, R3 + MOVD g_m(g), R8 + MOVD m_g0(R8), g + CMP g, R3 + BNE 2(PC) + BR runtime·badmcall(SB) + MOVD fn+0(FP), R4 + MOVD R4, CTR + MOVD (g_sched+gobuf_sp)(g), R1 + MOVDU R3, -8(R1) + MOVDU R0, -8(R1) + BL (CTR) + BR runtime·badmcall2(SB) + +/* + * support for morestack + */ + +// Called during function prolog when more stack is needed. +// Caller has already loaded: +// R3: framesize, R4: argsize, R5: LR +// +// The traceback routines see morestack on a g0 as being +// the top of a stack (for example, morestack calling newstack +// calling the scheduler calling newm calling gc), so we must +// record an argument size. For that purpose, it has no arguments. +TEXT runtime·morestack(SB),NOSPLIT,$0-0 + // Cannot grow scheduler stack (m->g0). + MOVD g_m(g), R7 + MOVD m_g0(R7), R8 + CMP g, R8 + BNE 2(PC) + BL runtime·abort(SB) + + MOVW R3, m_moreframesize(R7) + MOVW R4, m_moreargsize(R7) + + // Called from f. + // Set g->sched to context in f. + MOVD R11, (g_sched+gobuf_ctxt)(g) + MOVD R1, (g_sched+gobuf_sp)(g) + MOVD LR, R8 + MOVD R8, (g_sched+gobuf_pc)(g) + MOVD R5, (g_sched+gobuf_lr)(g) + + // Called from f. + // Set m->morebuf to f's caller. + MOVD R5, (m_morebuf+gobuf_pc)(R7) // f's caller's PC + MOVD R1, (m_morebuf+gobuf_sp)(R7) // f's caller's SP + MOVD $8(R1), R8 // f's argument pointer + MOVD R8, m_moreargp(R7) + MOVD g, (m_morebuf+gobuf_g)(R7) + + // Call newstack on m->g0's stack. + MOVD m_g0(R7), g + MOVD (g_sched+gobuf_sp)(g), R1 + BL runtime·newstack(SB) + + // Not reached, but make sure the return PC from the call to newstack + // is still in this function, and not the beginning of the next. + UNDEF + +TEXT runtime·morestack_noctxt(SB),NOSPLIT,$0-0 + MOVD R0, R11 + BR runtime·morestack(SB) + +// Called from panic. Mimics morestack, +// reuses stack growth code to create a frame +// with the desired args running the desired function. +// +// func call(fn *byte, arg *byte, argsize uint32). +TEXT runtime·newstackcall(SB), NOSPLIT, $-8-20 + // Save our caller's state as the PC and SP to restore when + // returning from f. + MOVD g_m(g), R5 + MOVD LR, R31 + MOVD R31, (m_morebuf+gobuf_pc)(R5) // our caller's PC + MOVD R1, (m_morebuf+gobuf_sp)(R5) // our caller's SP + MOVD g, (m_morebuf+gobuf_g)(R5) + + // Save our own state as the PC and SP to restore if this + // goroutine needs to be restarted. + MOVD $runtime·newstackcall(SB), R7 + MOVD R7, (g_sched+gobuf_pc)(g) + MOVD LR, R31 + MOVD R31, (g_sched+gobuf_lr)(g) + MOVD R1, (g_sched+gobuf_sp)(g) + + // Set up morestack arguments to call f on a new stack. + // We set f's frame size to 1, as a hint to newstack that + // this is a call from runtime.newstackcall. + // If it turns out that f needs a larger frame than the + // default stack, f's usual stack growth prolog will + // allocate a new segment (and recopy the arguments). + MOVD fn+0(FP), R7 + MOVD args+8(FP), R8 + MOVW n+16(FP), R9 + + MOVD R7, m_cret(R5) + MOVD R8, m_moreargp(R5) + MOVW R9, m_moreargsize(R5) + MOVD $1, R10 + MOVD R10, m_moreframesize(R5) + + // call newstack on m->g0's stack + MOVD m_g0(R5), g + MOVD (g_sched+gobuf_sp)(g), R1 + BR runtime·newstack(SB) + +// reflect·call: call a function with the given argument list +// func call(f *FuncVal, arg *byte, argsize uint32). +// we don't have variable-sized frames, so we use a small number +// of constant-sized-frame functions to encode a few bits of size in the pc. +// Caution: ugly multiline assembly macros in your future! + +#define DISPATCH(NAME,MAXSIZE) \ + MOVD $MAXSIZE, R31; \ + CMP R3, R31; \ + BGT 4(PC); \ + MOVD $runtime·NAME(SB), R31; \ + MOVD R31, CTR; \ + BR (CTR) + +// Note: can't just "BR runtime·NAME(SB)" - bad inlining results. +TEXT reflect·call(SB), NOSPLIT, $0-24 + MOVW argsize+16(FP), R3 + DISPATCH(call16, 16) + DISPATCH(call32, 32) + DISPATCH(call64, 64) + DISPATCH(call128, 128) + DISPATCH(call256, 256) + DISPATCH(call512, 512) + DISPATCH(call1024, 1024) + DISPATCH(call2048, 2048) + DISPATCH(call4096, 4096) + DISPATCH(call8192, 8192) + DISPATCH(call16384, 16384) + DISPATCH(call32768, 32768) + DISPATCH(call65536, 65536) + DISPATCH(call131072, 131072) + DISPATCH(call262144, 262144) + DISPATCH(call524288, 524288) + DISPATCH(call1048576, 1048576) + DISPATCH(call2097152, 2097152) + DISPATCH(call4194304, 4194304) + DISPATCH(call8388608, 8388608) + DISPATCH(call16777216, 16777216) + DISPATCH(call33554432, 33554432) + DISPATCH(call67108864, 67108864) + DISPATCH(call134217728, 134217728) + DISPATCH(call268435456, 268435456) + DISPATCH(call536870912, 536870912) + DISPATCH(call1073741824, 1073741824) + MOVD $runtime·badreflectcall(SB), R31 + MOVD R31, CTR + BR (CTR) + +// Argument map for the callXX frames. Each has one +// stack map (for the single call) with 3 arguments. +DATA gcargs_reflectcall<>+0x00(SB)/4, $1 // 1 stackmap +DATA gcargs_reflectcall<>+0x04(SB)/4, $6 // 3 args +DATA gcargs_reflectcall<>+0x08(SB)/4, $(const_BitsPointer+(const_BitsPointer<<2)+(const_BitsScalar<<4)) +GLOBL gcargs_reflectcall<>(SB),RODATA,$12 + +// callXX frames have no locals +DATA gclocals_reflectcall<>+0x00(SB)/4, $1 // 1 stackmap +DATA gclocals_reflectcall<>+0x04(SB)/4, $0 // 0 locals +GLOBL gclocals_reflectcall<>(SB),RODATA,$8 + +#define CALLFN(NAME,MAXSIZE) \ +TEXT runtime·NAME(SB), WRAPPER, $MAXSIZE-24; \ + FUNCDATA $FUNCDATA_ArgsPointerMaps,gcargs_reflectcall<>(SB); \ + FUNCDATA $FUNCDATA_LocalsPointerMaps,gclocals_reflectcall<>(SB);\ + /* copy arguments to stack */ \ + MOVD argptr+8(FP), R3; \ + MOVW argsize+16(FP), R4; \ + MOVD R1, R5; \ + ADD $(8-1), R5; \ + SUB $1, R3; \ + ADD R5, R4; \ + CMP R5, R4; \ + BEQ 4(PC); \ + MOVBZU 1(R3), R6; \ + MOVBZU R6, 1(R5); \ + BR -4(PC); \ + /* call function */ \ + MOVD f+0(FP), R31; \ + MOVD (R31), R31; \ + MOVD R31, CTR; \ + PCDATA $PCDATA_StackMapIndex, $0; \ + BL (CTR); \ + /* copy return values back */ \ + MOVD argptr+8(FP), R3; \ + MOVW argsize+16(FP), R4; \ + MOVW retoffset+20(FP), R5; \ + MOVD R1, R6; \ + ADD $(8-1), R6; \ + ADD R5, R6; \ + ADD R5, R3; \ + SUB R5, R4; \ + CMP R4, $0; \ + BEQ 9(PC); \ + SUB $1, R3; \ + SUB $1, R6; \ + ADD R3, R4; \ + CMP R3, R4; \ + BEQ 4(PC); \ + MOVBZU 1(R3), R5; \ + MOVBZU R5, 1(R6); \ + BR -4(PC); \ + RETURN + +CALLFN(call16, 16) +CALLFN(call32, 32) +CALLFN(call64, 64) +CALLFN(call128, 128) +CALLFN(call256, 256) +CALLFN(call512, 512) +CALLFN(call1024, 1024) +CALLFN(call2048, 2048) +CALLFN(call4096, 4096) +CALLFN(call8192, 8192) +CALLFN(call16384, 16384) +CALLFN(call32768, 32768) +CALLFN(call65536, 65536) +CALLFN(call131072, 131072) +CALLFN(call262144, 262144) +CALLFN(call524288, 524288) +CALLFN(call1048576, 1048576) +CALLFN(call2097152, 2097152) +CALLFN(call4194304, 4194304) +CALLFN(call8388608, 8388608) +CALLFN(call16777216, 16777216) +CALLFN(call33554432, 33554432) +CALLFN(call67108864, 67108864) +CALLFN(call134217728, 134217728) +CALLFN(call268435456, 268435456) +CALLFN(call536870912, 536870912) +CALLFN(call1073741824, 1073741824) + +// Return point when leaving stack. +// +// Lessstack can appear in stack traces for the same reason +// as morestack; in that context, it has 0 arguments. +TEXT runtime·lessstack(SB), NOSPLIT, $-8-0 + // Save return value in m->cret + MOVD g_m(g), R5 + MOVD R3, m_cret(R5) + + // Call oldstack on m->g0's stack. + MOVD m_g0(R5), g + MOVD (g_sched+gobuf_sp)(g), R1 + BL runtime·oldstack(SB) + +// bool cas(int32 *val, int32 old, int32 new) +// Atomically: +// if(*val == old){ +// *val = new; +// return 1; +// } else +// return 0; +TEXT runtime·cas(SB), NOSPLIT, $0-16 + MOVD p+0(FP), R3 + MOVW old+8(FP), R4 + MOVW new+12(FP), R5 + SYNC + LWAR (R3), R6 + CMPW R6, R4 + BNE 7(PC) + STWCCC R5, (R3) + BNE -5(PC) + MOVD $1, R3 + SYNC + ISYNC + RETURN + MOVD $0, R3 + BR -4(PC) + +// bool runtime·cas64(uint64 *val, uint64 old, uint64 new) +// Atomically: +// if(*val == *old){ +// *val = new; +// return 1; +// } else { +// return 0; +// } +TEXT runtime·cas64(SB), NOSPLIT, $0-24 + MOVD p+0(FP), R3 + MOVD old+8(FP), R4 + MOVD new+16(FP), R5 + SYNC + LDAR (R3), R6 + CMP R6, R4 + BNE 7(PC) + STDCCC R5, (R3) + BNE -5(PC) + MOVD $1, R3 + SYNC + ISYNC + RETURN + MOVD $0, R3 + BR -4(PC) + +// bool casp(void **val, void *old, void *new) +// Atomically: +// if(*val == old){ +// *val = new; +// return 1; +// } else +// return 0; +TEXT runtime·casp(SB), NOSPLIT, $0-24 + BR runtime·cas64(SB) + +// uint32 xadd(uint32 volatile *val, int32 delta) +// Atomically: +// *val += delta; +// return *val; +TEXT runtime·xadd(SB), NOSPLIT, $0-12 + MOVD p+0(FP), R4 + MOVW delta+8(FP), R5 + SYNC + LWAR (R4), R3 + ADD R5, R3 + STWCCC R3, (R4) + BNE -4(PC) + SYNC + ISYNC + MOVW R3, R3 + RETURN + +TEXT runtime·xadd64(SB), NOSPLIT, $0-16 + MOVD p+0(FP), R4 + MOVD delta+8(FP), R5 + SYNC + LDAR (R4), R3 + ADD R5, R3 + STDCCC R3, (R4) + BNE -4(PC) + SYNC + ISYNC + RETURN + +TEXT runtime·xchg(SB), NOSPLIT, $0-12 + MOVD p+0(FP), R4 + MOVW new+8(FP), R5 + SYNC + LWAR (R4), R3 + STWCCC R5, (R4) + BNE -3(PC) + SYNC + ISYNC + RETURN + +TEXT runtime·xchg64(SB), NOSPLIT, $0-16 + MOVD p+0(FP), R4 + MOVD new+8(FP), R5 + SYNC + LDAR (R4), R3 + STDCCC R5, (R4) + BNE -3(PC) + SYNC + ISYNC + RETURN + +TEXT runtime·xchgp(SB), NOSPLIT, $0-16 + BR runtime·xchg64(SB) + +TEXT runtime·procyield(SB),NOSPLIT,$0-0 + MOVD R0, 17(R0) + +TEXT runtime·atomicstorep(SB), NOSPLIT, $0-16 + BR runtime·atomicstore64(SB) + +TEXT runtime·atomicstore(SB), NOSPLIT, $0-12 + MOVD 0(FP), R3 + MOVW 8(FP), R4 + SYNC + MOVW R4, 0(R3) + RETURN + +TEXT runtime·atomicstore64(SB), NOSPLIT, $0-16 + MOVD 0(FP), R3 + MOVD 8(FP), R4 + SYNC + MOVD R4, 0(R3) + RETURN + +// void jmpdefer(fn, sp); +// called from deferreturn. +// 1. grab stored LR for caller +// 2. sub 4 bytes to get back to BL deferreturn +// 3. BR to fn +TEXT runtime·jmpdefer(SB), NOSPLIT, $-8-16 + MOVD 0(R1), R31 + SUB $4, R31 + MOVD R31, LR + + MOVD fn+0(FP), R11 + MOVD argp+8(FP), R1 + SUB $8, R1 + MOVD 0(R11), R3 + MOVD R3, CTR + BR (CTR) + +// Save state of caller into g->sched. Smashes R31. +TEXT gosave<>(SB),NOSPLIT,$-8 + MOVD LR, R31 + MOVD R31, (g_sched+gobuf_pc)(g) + MOVD R1, (g_sched+gobuf_sp)(g) + MOVD R0, (g_sched+gobuf_lr)(g) + MOVD R0, (g_sched+gobuf_ret)(g) + MOVD R0, (g_sched+gobuf_ctxt)(g) + RETURN + +// asmcgocall(void(*fn)(void*), void *arg) +// Call fn(arg) on the scheduler stack, +// aligned appropriately for the gcc ABI. +// See cgocall.c for more details. +TEXT runtime·asmcgocall(SB),NOSPLIT,$0-16 + MOVD R0, 21(R0) + +// cgocallback(void (*fn)(void*), void *frame, uintptr framesize) +// Turn the fn into a Go func (by taking its address) and call +// cgocallback_gofunc. +TEXT runtime·cgocallback(SB),NOSPLIT,$24-24 + MOVD R0, 22(R0) + +// cgocallback_gofunc(FuncVal*, void *frame, uintptr framesize) +// See cgocall.c for more details. +TEXT runtime·cgocallback_gofunc(SB),NOSPLIT,$8-24 + MOVD R0, 23(R0) + +// void setg(G*); set g. for use by needm. +TEXT runtime·setg(SB), NOSPLIT, $0-16 + MOVD R0, 24(R0) + +// void setg_gcc(G*); set g called from gcc. +TEXT setg_gcc<>(SB),NOSPLIT,$0 + MOVD R0, 25(R0) + +TEXT runtime·getcallerpc(SB),NOSPLIT,$-8-8 + MOVD 0(R1), R3 + RETURN + +TEXT runtime·gogetcallerpc(SB),NOSPLIT,$-8-16 + MOVD 0(R1), R3 + MOVD R3,ret+8(FP) + RETURN + +TEXT runtime·setcallerpc(SB),NOSPLIT,$-8-16 + MOVD x+8(FP),R3 // addr of first arg + MOVD R3, 0(R1) // set calling pc + RETURN + +TEXT runtime·getcallersp(SB),NOSPLIT,$0-8 + MOVD sp+0(FP), R3 + SUB $8, R3 + RETURN + +TEXT runtime·abort(SB),NOSPLIT,$-4-0 + MOVW (R0), R0 + UNDEF + +#define TBRL 268 +#define TBRU 269 /* Time base Upper/Lower */ + +// int64 runtime·cputicks(void) +TEXT runtime·cputicks(SB),NOSPLIT,$0-0 + MOVW SPR(TBRU), R4 + MOVW SPR(TBRL), R3 + MOVW SPR(TBRU), R5 + CMPW R4, R5 + BNE -4(PC) + SLD $32, R5 + OR R5, R3 + RETURN + +TEXT runtime·stackguard(SB),NOSPLIT,$0-16 + MOVD R1, R3 + MOVD R3, sp+0(FP) + MOVD g_stackguard(g), R3 + MOVD R3, limit+8(FP) + RETURN + +GLOBL runtime·tls0(SB), $64 + +// AES hashing not implemented for Power +TEXT runtime·aeshash(SB),NOSPLIT,$-8-0 + MOVW (R0), R1 +TEXT runtime·aeshash32(SB),NOSPLIT,$-8-0 + MOVW (R0), R1 +TEXT runtime·aeshash64(SB),NOSPLIT,$-8-0 + MOVW (R0), R1 +TEXT runtime·aeshashstr(SB),NOSPLIT,$-8-0 + MOVW (R0), R1 + +TEXT runtime·memeq(SB),NOSPLIT,$-8-24 + MOVD a+0(FP), R3 + MOVD b+8(FP), R4 + MOVD count+16(FP), R5 + SUB $1, R3 + SUB $1, R4 + ADD R3, R5, R8 +_next: + CMP R3, R8 + BNE 3(PC) + MOVD $1, R3 + RETURN + MOVBZU 1(R3), R6 + MOVBZU 1(R4), R7 + CMP R6, R7 + BEQ _next + + MOVD $0, R3 + RETURN + +TEXT runtime·gomemeq(SB),NOSPLIT,$0-25 + MOVD a+0(FP), R3 + MOVD b+8(FP), R4 + MOVD count+16(FP), R5 + SUB $1, R3 + SUB $1, R4 + ADD R3, R5, R8 +_next2: + CMP R3, R8 + BNE 4(PC) + MOVD $1, R3 + MOVB R3, ret+24(FP) + RETURN + MOVBZU 1(R3), R6 + MOVBZU 1(R4), R7 + CMP R6, R7 + BEQ _next2 + + MOVB R0, ret+24(FP) + RETURN + +// eqstring tests whether two strings are equal. +// See runtime_test.go:eqstring_generic for +// equivlaent Go code. +TEXT runtime·eqstring(SB),NOSPLIT,$0-33 + MOVD s1len+8(FP), R4 + MOVD s2len+24(FP), R5 + CMP R4, R5 + BNE str_noteq + + MOVD s1str+0(FP), R3 + MOVD s2str+16(FP), R4 + SUB $1, R3 + SUB $1, R4 + ADD R3, R5, R8 +eq_next: + CMP R3, R8 + BNE 4(PC) + MOVD $1, R3 + MOVB R3, ret+32(FP) + RETURN + MOVBZU 1(R3), R6 + MOVBZU 1(R4), R7 + CMP R6, R7 + BEQ eq_next +str_noteq: + MOVB R0, ret+32(FP) + RETURN + +// TODO: share code with memeq? +TEXT bytes·Equal(SB),NOSPLIT,$0-49 + MOVD a_len+8(FP), R3 + MOVD b_len+32(FP), R4 + + CMP R3, R4 // unequal lengths are not equal + BNE _notequal + + MOVD a+0(FP), R5 + MOVD b+24(FP), R6 + SUB $1, R5 + SUB $1, R6 + ADD R5, R3 // end-1 + +_byteseq_next: + CMP R5, R3 + BEQ _equal // reached the end + MOVBZU 1(R5), R4 + MOVBZU 1(R6), R7 + CMP R4, R7 + BEQ _byteseq_next + +_notequal: + MOVBZ R0, ret+48(FP) + RETURN + +_equal: + MOVD $1, R3 + MOVBZ R3, ret+48(FP) + RETURN + +TEXT bytes·IndexByte(SB),NOSPLIT,$0-40 + MOVD s+0(FP), R3 + MOVD s_len+8(FP), R4 + MOVBZ c+24(FP), R5 // byte to find + SUB $1, R3 + MOVD R3, R6 // store base-1 for later + ADD R3, R4 // end-1 + +_index_loop: + CMP R3, R4 + BEQ _index_notfound + MOVBZU 1(R3), R7 + CMP R7, R5 + BNE _index_loop + + SUB R6, R3 // remove base + MOVD R3, ret+32(FP) + RETURN + +_index_notfound: + MOVW $-1, R3 + MOVW R3, ret+32(FP) + RETURN + +TEXT strings·IndexByte(SB),NOSPLIT,$0 + MOVD p+0(FP), R3 + MOVD b_len+8(FP), R4 + MOVBZ c+16(FP), R5 // byte to find + SUB $1, R3 + MOVD R3, R6 // store base-1 for later + ADD R3, R4 // end-1 + +_index2_loop: + CMP R3, R4 + BEQ _index2_notfound + MOVBZU 1(R3), R7 + CMP R7, R5 + BNE _index2_loop + + SUB R6, R3 // remove base + MOVD R3, ret+24(FP) + RETURN + +_index2_notfound: + MOVW $-1, R3 + MOVW R3, ret+24(FP) + RETURN + + +TEXT runtime·timenow(SB), NOSPLIT, $0-0 + BR time·now(SB) + +// A Duff's device for zeroing memory. +// The compiler jumps to computed addresses within +// this routine to zero chunks of memory. Do not +// change this code without also changing the code +// in ../../cmd/9g/ggen.c:/^clearfat. +// R0: always zero +// R3 (aka REGRT1): ptr to memory to be zeroed - 8 +// R3 is updated as a side effect. +TEXT runtime·duffzero(SB), NOSPLIT, $-8-0 + MOVDU R0, 8(R3) + MOVDU R0, 8(R3) + MOVDU R0, 8(R3) + MOVDU R0, 8(R3) + MOVDU R0, 8(R3) + MOVDU R0, 8(R3) + MOVDU R0, 8(R3) + MOVDU R0, 8(R3) + MOVDU R0, 8(R3) + MOVDU R0, 8(R3) + MOVDU R0, 8(R3) + MOVDU R0, 8(R3) + MOVDU R0, 8(R3) + MOVDU R0, 8(R3) + MOVDU R0, 8(R3) + MOVDU R0, 8(R3) + MOVDU R0, 8(R3) + MOVDU R0, 8(R3) + MOVDU R0, 8(R3) + MOVDU R0, 8(R3) + MOVDU R0, 8(R3) + MOVDU R0, 8(R3) + MOVDU R0, 8(R3) + MOVDU R0, 8(R3) + MOVDU R0, 8(R3) + MOVDU R0, 8(R3) + MOVDU R0, 8(R3) + MOVDU R0, 8(R3) + MOVDU R0, 8(R3) + MOVDU R0, 8(R3) + MOVDU R0, 8(R3) + MOVDU R0, 8(R3) + MOVDU R0, 8(R3) + MOVDU R0, 8(R3) + MOVDU R0, 8(R3) + MOVDU R0, 8(R3) + MOVDU R0, 8(R3) + MOVDU R0, 8(R3) + MOVDU R0, 8(R3) + MOVDU R0, 8(R3) + MOVDU R0, 8(R3) + MOVDU R0, 8(R3) + MOVDU R0, 8(R3) + MOVDU R0, 8(R3) + MOVDU R0, 8(R3) + MOVDU R0, 8(R3) + MOVDU R0, 8(R3) + MOVDU R0, 8(R3) + MOVDU R0, 8(R3) + MOVDU R0, 8(R3) + MOVDU R0, 8(R3) + MOVDU R0, 8(R3) + MOVDU R0, 8(R3) + MOVDU R0, 8(R3) + MOVDU R0, 8(R3) + MOVDU R0, 8(R3) + MOVDU R0, 8(R3) + MOVDU R0, 8(R3) + MOVDU R0, 8(R3) + MOVDU R0, 8(R3) + MOVDU R0, 8(R3) + MOVDU R0, 8(R3) + MOVDU R0, 8(R3) + MOVDU R0, 8(R3) + MOVDU R0, 8(R3) + MOVDU R0, 8(R3) + MOVDU R0, 8(R3) + MOVDU R0, 8(R3) + MOVDU R0, 8(R3) + MOVDU R0, 8(R3) + MOVDU R0, 8(R3) + MOVDU R0, 8(R3) + MOVDU R0, 8(R3) + MOVDU R0, 8(R3) + MOVDU R0, 8(R3) + MOVDU R0, 8(R3) + MOVDU R0, 8(R3) + MOVDU R0, 8(R3) + MOVDU R0, 8(R3) + MOVDU R0, 8(R3) + MOVDU R0, 8(R3) + MOVDU R0, 8(R3) + MOVDU R0, 8(R3) + MOVDU R0, 8(R3) + MOVDU R0, 8(R3) + MOVDU R0, 8(R3) + MOVDU R0, 8(R3) + MOVDU R0, 8(R3) + MOVDU R0, 8(R3) + MOVDU R0, 8(R3) + MOVDU R0, 8(R3) + MOVDU R0, 8(R3) + MOVDU R0, 8(R3) + MOVDU R0, 8(R3) + MOVDU R0, 8(R3) + MOVDU R0, 8(R3) + MOVDU R0, 8(R3) + MOVDU R0, 8(R3) + MOVDU R0, 8(R3) + MOVDU R0, 8(R3) + MOVDU R0, 8(R3) + MOVDU R0, 8(R3) + MOVDU R0, 8(R3) + MOVDU R0, 8(R3) + MOVDU R0, 8(R3) + MOVDU R0, 8(R3) + MOVDU R0, 8(R3) + MOVDU R0, 8(R3) + MOVDU R0, 8(R3) + MOVDU R0, 8(R3) + MOVDU R0, 8(R3) + MOVDU R0, 8(R3) + MOVDU R0, 8(R3) + MOVDU R0, 8(R3) + MOVDU R0, 8(R3) + MOVDU R0, 8(R3) + MOVDU R0, 8(R3) + MOVDU R0, 8(R3) + MOVDU R0, 8(R3) + MOVDU R0, 8(R3) + MOVDU R0, 8(R3) + MOVDU R0, 8(R3) + MOVDU R0, 8(R3) + MOVDU R0, 8(R3) + MOVDU R0, 8(R3) + MOVDU R0, 8(R3) + MOVDU R0, 8(R3) + MOVDU R0, 8(R3) + RETURN + +TEXT runtime·fastrand2(SB), NOSPLIT, $0-4 + MOVD g_m(g), R4 + MOVD m_fastrand(R4), R3 + ADD R3, R3 + CMP R3, $0 + BGE 2(PC) + XOR $0x88888eef, R3 + MOVD R3, m_fastrand(R4) + MOVD R3, ret+0(FP) + RETURN + +// The gohash and goeq trampolines are necessary while we have +// both Go and C calls to alg functions. Once we move all call +// sites to Go, we can redo the hash/eq functions to use the +// Go calling convention and remove these. + +// convert call to: +// func (alg unsafe.Pointer, p unsafe.Pointer, size uintpr, seed uintptr) uintptr +// to: +// func (hash *uintptr, size uintptr, p unsafe.Pointer) +TEXT runtime·gohash(SB), NOSPLIT, $24-40 + FUNCDATA $FUNCDATA_ArgsPointerMaps,gcargs_gohash<>(SB) + FUNCDATA $FUNCDATA_LocalsPointerMaps,gclocals_gohash<>(SB) + MOVD a+0(FP), R3 + MOVD alg_hash(R3), R3 + MOVD R3, CTR + MOVD p+8(FP), R4 + MOVD size+16(FP), R5 + MOVD seed+24(FP), R6 + MOVD R6, ret+32(FP) + MOVD $ret+32(FP), R7 + MOVD R7, 8(R1) + MOVD R5, 16(R1) + MOVD R4, 24(R1) + PCDATA $PCDATA_StackMapIndex, $0 + BL (CTR) + RETURN + +DATA gcargs_gohash<>+0x00(SB)/4, $1 // 1 stackmap +DATA gcargs_gohash<>+0x04(SB)/4, $10 // 5 args +DATA gcargs_gohash<>+0x08(SB)/4, $(const_BitsPointer+(const_BitsPointer<<2)) +GLOBL gcargs_gohash<>(SB),RODATA,$12 + +DATA gclocals_gohash<>+0x00(SB)/4, $1 // 1 stackmap +DATA gclocals_gohash<>+0x04(SB)/4, $0 // 0 locals +GLOBL gclocals_gohash<>(SB),RODATA,$8 + +// convert call to: +// func (alg unsafe.Pointer, p, q unsafe.Pointer, size uintptr) bool +// to: +// func (eq *bool, size uintptr, p, q unsafe.Pointer) +TEXT runtime·goeq(SB), NOSPLIT, $32-33 + FUNCDATA $FUNCDATA_ArgsPointerMaps,gcargs_goeq<>(SB) + FUNCDATA $FUNCDATA_LocalsPointerMaps,gclocals_goeq<>(SB) + MOVD alg+0(FP), R3 + MOVD alg_equal(R3), R3 + MOVD R3, CTR + MOVD p+8(FP), R4 + MOVD q+16(FP), R5 + MOVD size+24(FP), R6 + MOVD $ret+32(FP), R7 + MOVD R7, 8(R1) + MOVD R6, 16(R1) + MOVD R5, 24(R1) + MOVD R4, 32(R1) + PCDATA $PCDATA_StackMapIndex, $0 + BL (CTR) + RETURN + +DATA gcargs_goeq<>+0x00(SB)/4, $1 // 1 stackmap +DATA gcargs_goeq<>+0x04(SB)/4, $10 // 5 args +DATA gcargs_goeq<>+0x08(SB)/4, $(const_BitsPointer+(const_BitsPointer<<2)+(const_BitsPointer<<4)) +GLOBL gcargs_goeq<>(SB),RODATA,$12 + +DATA gclocals_goeq<>+0x00(SB)/4, $1 // 1 stackmap +DATA gclocals_goeq<>+0x04(SB)/4, $0 // 0 locals +GLOBL gclocals_goeq<>(SB),RODATA,$8 diff --git a/src/pkg/runtime/atomic_power64x.s b/src/pkg/runtime/atomic_power64x.s new file mode 100644 index 0000000000..c08590ac97 --- /dev/null +++ b/src/pkg/runtime/atomic_power64x.s @@ -0,0 +1,37 @@ +// 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. + +// +build power64 power64le + +#include "../../cmd/ld/textflag.h" + +// uint32 runtime·atomicload(uint32 volatile* addr) +TEXT ·atomicload(SB),NOSPLIT,$-8-8 + MOVD 0(FP), R3 + SYNC + MOVWZ 0(R3), R3 + CMPW R3, R3, CR7 + BC 4, 30, 1(PC) // bne- cr7,0x4 + ISYNC + RETURN + +// uint64 runtime·atomicload64(uint64 volatile* addr) +TEXT ·atomicload64(SB),NOSPLIT,$-8-8 + MOVD 0(FP), R3 + SYNC + MOVD 0(R3), R3 + CMP R3, R3, CR7 + BC 4, 30, 1(PC) // bne- cr7,0x4 + ISYNC + RETURN + +// void *runtime·atomicloadp(void *volatile *addr) +TEXT ·atomicloadp(SB),NOSPLIT,$-8-8 + MOVD 0(FP), R3 + SYNC + MOVD 0(R3), R3 + CMP R3, R3, CR7 + BC 4, 30, 1(PC) // bne- cr7,0x4 + ISYNC + RETURN diff --git a/src/pkg/runtime/memclr_power64x.s b/src/pkg/runtime/memclr_power64x.s new file mode 100644 index 0000000000..4a2437c209 --- /dev/null +++ b/src/pkg/runtime/memclr_power64x.s @@ -0,0 +1,20 @@ +// 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. + +// +build power64 power64le + +#include "../../cmd/ld/textflag.h" + +// void runtime·memclr(void*, uintptr) +TEXT runtime·memclr(SB),NOSPLIT,$0-16 + MOVD ptr+0(FP), R3 + MOVD n+8(FP), R4 + CMP R4, $0 + BEQ done + SUB $1, R3 + MOVD R4, CTR + MOVBU R0, 1(R3) + BC 25, 0, -1(PC) // bdnz+ $-4 +done: + RETURN diff --git a/src/pkg/runtime/memmove_power64x.s b/src/pkg/runtime/memmove_power64x.s new file mode 100644 index 0000000000..b618f0ad7b --- /dev/null +++ b/src/pkg/runtime/memmove_power64x.s @@ -0,0 +1,40 @@ +// 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. + +// +build power64 power64le + +#include "../../cmd/ld/textflag.h" + +// void runtime·memmove(void*, void*, uintptr) +TEXT runtime·memmove(SB), NOSPLIT, $-8-24 + MOVD to+0(FP), R3 + MOVD from+8(FP), R4 + MOVD n+16(FP), R5 + CMP R5, $0 + BNE check + RETURN + +check: + CMP R3, R4 + BGT backward + + SUB $1, R3 + ADD R3, R5 + SUB $1, R4 +loop: + MOVBU 1(R4), R6 + MOVBU R6, 1(R3) + CMP R3, R5 + BNE loop + RETURN + +backward: + ADD R5, R4 + ADD R3, R5 +loop1: + MOVBU -1(R4), R6 + MOVBU R6, -1(R5) + CMP R3, R5 + BNE loop1 + RETURN diff --git a/src/pkg/runtime/rt0_linux_power64.s b/src/pkg/runtime/rt0_linux_power64.s new file mode 100644 index 0000000000..e944bcdbf8 --- /dev/null +++ b/src/pkg/runtime/rt0_linux_power64.s @@ -0,0 +1,17 @@ +#include "../../cmd/ld/textflag.h" + +// actually a function descriptor for _main<>(SB) +TEXT _rt0_power64_linux(SB),7,$0 + DWORD $_main<>(SB) + DWORD $0 + DWORD $0 + +TEXT _main<>(SB),NOSPLIT,$-8 + MOVD 0(R1), R3 // argc + ADD $8, R1, R4 // argv + BR main(SB) + +TEXT main(SB),NOSPLIT,$-8 + MOVD $_rt0_go(SB), R31 + MOVD R31, CTR + BR (CTR) diff --git a/src/pkg/runtime/rt0_linux_power64le.s b/src/pkg/runtime/rt0_linux_power64le.s new file mode 100644 index 0000000000..051815dbce --- /dev/null +++ b/src/pkg/runtime/rt0_linux_power64le.s @@ -0,0 +1,14 @@ +#include "../../cmd/ld/textflag.h" + +TEXT _rt0_power64le_linux(SB),7,$0 + BR _main<>(SB) + +TEXT _main<>(SB),NOSPLIT,$-8 + MOVD 0(R1), R3 // argc + ADD $8, R1, R4 // argv + BR main(SB) + +TEXT main(SB),NOSPLIT,$-8 + MOVD $_rt0_go(SB), R31 + MOVD R31, CTR + BR (CTR) diff --git a/src/pkg/runtime/signal_linux_power64.h b/src/pkg/runtime/signal_linux_power64.h new file mode 100644 index 0000000000..8406489209 --- /dev/null +++ b/src/pkg/runtime/signal_linux_power64.h @@ -0,0 +1,49 @@ +// 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. + +#define SIG_REGS(ctxt) (*((Sigcontext*)&((Ucontext*)(ctxt))->uc_mcontext)->regs) + +#define SIG_R0(info, ctxt) (SIG_REGS(ctxt).gpr[0]) +#define SIG_R1(info, ctxt) (SIG_REGS(ctxt).gpr[1]) +#define SIG_R2(info, ctxt) (SIG_REGS(ctxt).gpr[2]) +#define SIG_R3(info, ctxt) (SIG_REGS(ctxt).gpr[3]) +#define SIG_R4(info, ctxt) (SIG_REGS(ctxt).gpr[4]) +#define SIG_R5(info, ctxt) (SIG_REGS(ctxt).gpr[5]) +#define SIG_R6(info, ctxt) (SIG_REGS(ctxt).gpr[6]) +#define SIG_R7(info, ctxt) (SIG_REGS(ctxt).gpr[7]) +#define SIG_R8(info, ctxt) (SIG_REGS(ctxt).gpr[8]) +#define SIG_R9(info, ctxt) (SIG_REGS(ctxt).gpr[9]) +#define SIG_R10(info, ctxt) (SIG_REGS(ctxt).gpr[10]) +#define SIG_R11(info, ctxt) (SIG_REGS(ctxt).gpr[11]) +#define SIG_R12(info, ctxt) (SIG_REGS(ctxt).gpr[12]) +#define SIG_R13(info, ctxt) (SIG_REGS(ctxt).gpr[13]) +#define SIG_R14(info, ctxt) (SIG_REGS(ctxt).gpr[14]) +#define SIG_R15(info, ctxt) (SIG_REGS(ctxt).gpr[15]) +#define SIG_R16(info, ctxt) (SIG_REGS(ctxt).gpr[16]) +#define SIG_R17(info, ctxt) (SIG_REGS(ctxt).gpr[17]) +#define SIG_R18(info, ctxt) (SIG_REGS(ctxt).gpr[18]) +#define SIG_R19(info, ctxt) (SIG_REGS(ctxt).gpr[19]) +#define SIG_R20(info, ctxt) (SIG_REGS(ctxt).gpr[20]) +#define SIG_R21(info, ctxt) (SIG_REGS(ctxt).gpr[21]) +#define SIG_R22(info, ctxt) (SIG_REGS(ctxt).gpr[22]) +#define SIG_R23(info, ctxt) (SIG_REGS(ctxt).gpr[23]) +#define SIG_R24(info, ctxt) (SIG_REGS(ctxt).gpr[24]) +#define SIG_R25(info, ctxt) (SIG_REGS(ctxt).gpr[25]) +#define SIG_R26(info, ctxt) (SIG_REGS(ctxt).gpr[26]) +#define SIG_R27(info, ctxt) (SIG_REGS(ctxt).gpr[27]) +#define SIG_R28(info, ctxt) (SIG_REGS(ctxt).gpr[28]) +#define SIG_R29(info, ctxt) (SIG_REGS(ctxt).gpr[29]) +#define SIG_R30(info, ctxt) (SIG_REGS(ctxt).gpr[30]) +#define SIG_R31(info, ctxt) (SIG_REGS(ctxt).gpr[31]) + +#define SIG_SP(info, ctxt) (SIG_REGS(ctxt).gpr[1]) +#define SIG_PC(info, ctxt) (SIG_REGS(ctxt).nip) +#define SIG_TRAP(info, ctxt) (SIG_REGS(ctxt).trap) +#define SIG_CTR(info, ctxt) (SIG_REGS(ctxt).ctr) +#define SIG_LINK(info, ctxt) (SIG_REGS(ctxt).link) +#define SIG_XER(info, ctxt) (SIG_REGS(ctxt).xer) +#define SIG_CCR(info, ctxt) (SIG_REGS(ctxt).ccr) + +#define SIG_CODE0(info, ctxt) ((uintptr)(info)->si_code) +#define SIG_FAULT(info, ctxt) (SIG_REGS(ctxt).dar) diff --git a/src/pkg/runtime/signal_linux_power64le.h b/src/pkg/runtime/signal_linux_power64le.h new file mode 100644 index 0000000000..8406489209 --- /dev/null +++ b/src/pkg/runtime/signal_linux_power64le.h @@ -0,0 +1,49 @@ +// 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. + +#define SIG_REGS(ctxt) (*((Sigcontext*)&((Ucontext*)(ctxt))->uc_mcontext)->regs) + +#define SIG_R0(info, ctxt) (SIG_REGS(ctxt).gpr[0]) +#define SIG_R1(info, ctxt) (SIG_REGS(ctxt).gpr[1]) +#define SIG_R2(info, ctxt) (SIG_REGS(ctxt).gpr[2]) +#define SIG_R3(info, ctxt) (SIG_REGS(ctxt).gpr[3]) +#define SIG_R4(info, ctxt) (SIG_REGS(ctxt).gpr[4]) +#define SIG_R5(info, ctxt) (SIG_REGS(ctxt).gpr[5]) +#define SIG_R6(info, ctxt) (SIG_REGS(ctxt).gpr[6]) +#define SIG_R7(info, ctxt) (SIG_REGS(ctxt).gpr[7]) +#define SIG_R8(info, ctxt) (SIG_REGS(ctxt).gpr[8]) +#define SIG_R9(info, ctxt) (SIG_REGS(ctxt).gpr[9]) +#define SIG_R10(info, ctxt) (SIG_REGS(ctxt).gpr[10]) +#define SIG_R11(info, ctxt) (SIG_REGS(ctxt).gpr[11]) +#define SIG_R12(info, ctxt) (SIG_REGS(ctxt).gpr[12]) +#define SIG_R13(info, ctxt) (SIG_REGS(ctxt).gpr[13]) +#define SIG_R14(info, ctxt) (SIG_REGS(ctxt).gpr[14]) +#define SIG_R15(info, ctxt) (SIG_REGS(ctxt).gpr[15]) +#define SIG_R16(info, ctxt) (SIG_REGS(ctxt).gpr[16]) +#define SIG_R17(info, ctxt) (SIG_REGS(ctxt).gpr[17]) +#define SIG_R18(info, ctxt) (SIG_REGS(ctxt).gpr[18]) +#define SIG_R19(info, ctxt) (SIG_REGS(ctxt).gpr[19]) +#define SIG_R20(info, ctxt) (SIG_REGS(ctxt).gpr[20]) +#define SIG_R21(info, ctxt) (SIG_REGS(ctxt).gpr[21]) +#define SIG_R22(info, ctxt) (SIG_REGS(ctxt).gpr[22]) +#define SIG_R23(info, ctxt) (SIG_REGS(ctxt).gpr[23]) +#define SIG_R24(info, ctxt) (SIG_REGS(ctxt).gpr[24]) +#define SIG_R25(info, ctxt) (SIG_REGS(ctxt).gpr[25]) +#define SIG_R26(info, ctxt) (SIG_REGS(ctxt).gpr[26]) +#define SIG_R27(info, ctxt) (SIG_REGS(ctxt).gpr[27]) +#define SIG_R28(info, ctxt) (SIG_REGS(ctxt).gpr[28]) +#define SIG_R29(info, ctxt) (SIG_REGS(ctxt).gpr[29]) +#define SIG_R30(info, ctxt) (SIG_REGS(ctxt).gpr[30]) +#define SIG_R31(info, ctxt) (SIG_REGS(ctxt).gpr[31]) + +#define SIG_SP(info, ctxt) (SIG_REGS(ctxt).gpr[1]) +#define SIG_PC(info, ctxt) (SIG_REGS(ctxt).nip) +#define SIG_TRAP(info, ctxt) (SIG_REGS(ctxt).trap) +#define SIG_CTR(info, ctxt) (SIG_REGS(ctxt).ctr) +#define SIG_LINK(info, ctxt) (SIG_REGS(ctxt).link) +#define SIG_XER(info, ctxt) (SIG_REGS(ctxt).xer) +#define SIG_CCR(info, ctxt) (SIG_REGS(ctxt).ccr) + +#define SIG_CODE0(info, ctxt) ((uintptr)(info)->si_code) +#define SIG_FAULT(info, ctxt) (SIG_REGS(ctxt).dar) diff --git a/src/pkg/runtime/signal_power64x.c b/src/pkg/runtime/signal_power64x.c new file mode 100644 index 0000000000..89c5c78485 --- /dev/null +++ b/src/pkg/runtime/signal_power64x.c @@ -0,0 +1,137 @@ +// 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. + +// +build linux +// +build power64 power64le + +#include "runtime.h" +#include "defs_GOOS_GOARCH.h" +#include "os_GOOS.h" +#include "signal_GOOS_GOARCH.h" +#include "signals_GOOS.h" + +void +runtime·dumpregs(Siginfo *info, void *ctxt) +{ + USED(info); USED(ctxt); + runtime·printf("r0 %X\t", SIG_R0(info, ctxt)); + runtime·printf("r1 %X\n", SIG_R1(info, ctxt)); + runtime·printf("r2 %X\t", SIG_R2(info, ctxt)); + runtime·printf("r3 %X\n", SIG_R3(info, ctxt)); + runtime·printf("r4 %X\t", SIG_R4(info, ctxt)); + runtime·printf("r5 %X\n", SIG_R5(info, ctxt)); + runtime·printf("r6 %X\t", SIG_R6(info, ctxt)); + runtime·printf("r7 %X\n", SIG_R7(info, ctxt)); + runtime·printf("r8 %X\t", SIG_R8(info, ctxt)); + runtime·printf("r9 %X\n", SIG_R9(info, ctxt)); + runtime·printf("r10 %X\t", SIG_R10(info, ctxt)); + runtime·printf("r11 %X\n", SIG_R11(info, ctxt)); + runtime·printf("r12 %X\t", SIG_R12(info, ctxt)); + runtime·printf("r13 %X\n", SIG_R13(info, ctxt)); + runtime·printf("r14 %X\t", SIG_R14(info, ctxt)); + runtime·printf("r15 %X\n", SIG_R15(info, ctxt)); + runtime·printf("r16 %X\t", SIG_R16(info, ctxt)); + runtime·printf("r17 %X\n", SIG_R17(info, ctxt)); + runtime·printf("r18 %X\t", SIG_R18(info, ctxt)); + runtime·printf("r19 %X\n", SIG_R19(info, ctxt)); + runtime·printf("r20 %X\t", SIG_R20(info, ctxt)); + runtime·printf("r21 %X\n", SIG_R21(info, ctxt)); + runtime·printf("r22 %X\t", SIG_R22(info, ctxt)); + runtime·printf("r23 %X\n", SIG_R23(info, ctxt)); + runtime·printf("r24 %X\t", SIG_R24(info, ctxt)); + runtime·printf("r25 %X\n", SIG_R25(info, ctxt)); + runtime·printf("r26 %X\t", SIG_R26(info, ctxt)); + runtime·printf("r27 %X\n", SIG_R27(info, ctxt)); + runtime·printf("r28 %X\t", SIG_R28(info, ctxt)); + runtime·printf("r29 %X\n", SIG_R29(info, ctxt)); + runtime·printf("r30 %X\t", SIG_R30(info, ctxt)); + runtime·printf("r31 %X\n", SIG_R31(info, ctxt)); + runtime·printf("pc %X\t", SIG_PC(info, ctxt)); + runtime·printf("ctr %X\n", SIG_CTR(info, ctxt)); + runtime·printf("link %X\t", SIG_LINK(info, ctxt)); + runtime·printf("xer %X\n", SIG_XER(info, ctxt)); + runtime·printf("ccr %X\t", SIG_CCR(info, ctxt)); + runtime·printf("trap %X\n", SIG_TRAP(info, ctxt)); +} + +void +runtime·sighandler(int32 sig, Siginfo *info, void *ctxt, G *gp) +{ + SigTab *t; + bool crash; + + if(sig == SIGPROF) { + runtime·sigprof((uint8*)SIG_PC(info, ctxt), (uint8*)SIG_SP(info, ctxt), (uint8*)SIG_LINK(info, ctxt), gp, g->m); + return; + } + t = &runtime·sigtab[sig]; + if(SIG_CODE0(info, ctxt) != SI_USER && (t->flags & SigPanic)) { + // Make it look like a call to the signal func. + // Have to pass arguments out of band since + // augmenting the stack frame would break + // the unwinding code. + gp->sig = sig; + gp->sigcode0 = SIG_CODE0(info, ctxt); + gp->sigcode1 = SIG_FAULT(info, ctxt); + gp->sigpc = SIG_PC(info, ctxt); + + // We arrange link, and pc to pretend the panicking + // function calls sigpanic directly. + // Always save LINK to stack so that panics in leaf + // functions are correctly handled. This smashes + // the stack frame but we're not going back there + // anyway. + SIG_SP(info, ctxt) -= sizeof(uintptr); + *(uintptr*)SIG_SP(info, ctxt) = SIG_LINK(info, ctxt); + // 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(gp->sigpc != 0) + SIG_LINK(info, ctxt) = gp->sigpc; + // In case we are panicking from external C code + SIG_R0(info, ctxt) = 0; + SIG_R30(info, ctxt) = (uintptr)gp; + SIG_PC(info, ctxt) = (uintptr)runtime·sigpanic; + return; + } + + if(SIG_CODE0(info, ctxt) == SI_USER || (t->flags & SigNotify)) + if(runtime·sigsend(sig)) + return; + if(t->flags & SigKill) + runtime·exit(2); + if(!(t->flags & SigThrow)) + return; + + g->m->throwing = 1; + g->m->caughtsig = gp; + if(runtime·panicking) // traceback already printed + runtime·exit(2); + runtime·panicking = 1; + + 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", SIG_PC(info, ctxt)); + if(g->m->lockedg != nil && g->m->ncgo > 0 && gp == g->m->g0) { + runtime·printf("signal arrived during cgo execution\n"); + gp = g->m->lockedg; + } + runtime·printf("\n"); + + if(runtime·gotraceback(&crash)){ + runtime·goroutineheader(gp); + runtime·traceback(SIG_PC(info, ctxt), SIG_SP(info, ctxt), SIG_LINK(info, ctxt), gp); + runtime·tracebackothers(gp); + runtime·printf("\n"); + runtime·dumpregs(info, ctxt); + } + + if(crash) + runtime·crash(); + + runtime·exit(2); +} diff --git a/src/pkg/runtime/sys_linux_power64x.s b/src/pkg/runtime/sys_linux_power64x.s new file mode 100644 index 0000000000..c0c41efa95 --- /dev/null +++ b/src/pkg/runtime/sys_linux_power64x.s @@ -0,0 +1,369 @@ +// 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. + +// +build linux +// +build power64 power64le + +// +// System calls and other sys.stuff for Power64, Linux +// + +#include "zasm_GOOS_GOARCH.h" +#include "../../cmd/ld/textflag.h" + +#define SYS_exit 1 +#define SYS_read 3 +#define SYS_write 4 +#define SYS_open 5 +#define SYS_close 6 +#define SYS_fcntl 55 +#define SYS_gettimeofday 78 +#define SYS_select 82 // always return -ENOSYS +#define SYS_mmap 90 +#define SYS_munmap 91 +#define SYS_setitimer 104 +#define SYS_clone 120 +#define SYS_newselect 142 +#define SYS_sched_yield 158 +#define SYS_rt_sigreturn 172 +#define SYS_rt_sigaction 173 +#define SYS_rt_sigprocmask 174 +#define SYS_sigaltstack 185 +#define SYS_ugetrlimit 190 +#define SYS_madvise 205 +#define SYS_mincore 206 +#define SYS_gettid 207 +#define SYS_tkill 208 +#define SYS_futex 221 +#define SYS_sched_getaffinity 223 +#define SYS_exit_group 234 +#define SYS_epoll_create 236 +#define SYS_epoll_ctl 237 +#define SYS_epoll_wait 238 +#define SYS_clock_gettime 246 +#define SYS_epoll_create1 315 + +TEXT runtime·exit(SB),NOSPLIT,$-8-8 + MOVW 8(R1), R3 + SYSCALL $SYS_exit_group + RETURN + +TEXT runtime·exit1(SB),NOSPLIT,$-8-8 + MOVW 8(R1), R3 + SYSCALL $SYS_exit + RETURN + +TEXT runtime·open(SB),NOSPLIT,$-8-16 + MOVD 8(R1), R3 + MOVW 16(R1), R4 + MOVW 20(R1), R5 + SYSCALL $SYS_open + RETURN + +TEXT runtime·close(SB),NOSPLIT,$-8-16 + MOVW 8(R1), R3 + SYSCALL $SYS_close + RETURN + +TEXT runtime·write(SB),NOSPLIT,$-8-24 + MOVD 8(R1), R3 + MOVD 16(R1), R4 + MOVW 24(R1), R5 + SYSCALL $SYS_write + RETURN + +TEXT runtime·read(SB),NOSPLIT,$-8-24 + MOVW 8(R1), R3 + MOVD 16(R1), R4 + MOVW 24(R1), R5 + SYSCALL $SYS_read + RETURN + +TEXT runtime·getrlimit(SB),NOSPLIT,$-8-24 + MOVW 8(R1), R3 + MOVD 16(R1), R4 + SYSCALL $SYS_ugetrlimit // ??? why not use SYS_getrlimit + RETURN + +TEXT runtime·usleep(SB),NOSPLIT,$-8-16 + MOVW usec+0(FP), R3 + MOVD R3, R5 + MOVW $1000000, R4 + DIVD R4, R3 + MOVD R3, 0(R1) + MULLD R3, R4 + SUB R4, R5 + MOVD R5, 8(R1) + + // select(0, 0, 0, 0, &tv) + MOVW $0, R3 + MOVW $0, R4 + MOVW $0, R5 + MOVW $0, R6 + MOVD R1, R7 + SYSCALL $SYS_newselect + RETURN + +TEXT runtime·raise(SB),NOSPLIT,$-8 + SYSCALL $SYS_gettid + MOVW R3, R3 // arg 1 tid + MOVW sig+0(FP), R4 // arg 2 + SYSCALL $SYS_tkill + RETURN + +TEXT runtime·setitimer(SB),NOSPLIT,$-8-24 + MOVW 8(R1), R3 + MOVD 16(R1), R4 + MOVD 24(R1), R5 + SYSCALL $SYS_setitimer + RETURN + +TEXT runtime·mincore(SB),NOSPLIT,$-8-24 + MOVD 8(R1), R3 + MOVD 16(R1), R4 + MOVD 24(R1), R5 + SYSCALL $SYS_mincore + RETURN + +// func now() (sec int64, nsec int32) +TEXT time·now(SB),NOSPLIT,$16 + MOVD $0(R1), R3 + MOVD $0, R4 + SYSCALL $SYS_gettimeofday + MOVD 0(R1), R3 // sec + MOVW 8(R1), R5 // usec + MOVD $1000, R4 + MULLD R4, R5 + MOVD R3, sec+0(FP) + MOVW R5, nsec+8(FP) + RETURN + +TEXT runtime·nanotime(SB),NOSPLIT,$16 + MOVW $1, R3 // CLOCK_MONOTONIC + MOVD $0(R1), R4 + SYSCALL $SYS_clock_gettime + MOVD 0(R1), R3 // sec + MOVD 8(R1), R5 // nsec + // sec is in R3, nsec in R5 + // return nsec in R3 + MOVD $1000000000, R4 + MULLD R4, R3 + ADD R5, R3 + RETURN + +TEXT runtime·rtsigprocmask(SB),NOSPLIT,$-8-32 + MOVW 8(R1), R3 + MOVD 16(R1), R4 + MOVD 24(R1), R5 + MOVW 32(R1), R6 + SYSCALL $SYS_rt_sigprocmask + BVC 2(PC) + MOVD R0, 0xf1(R0) // crash + RETURN + +TEXT runtime·rt_sigaction(SB),NOSPLIT,$-8-32 + MOVD 8(R1), R3 + MOVD 16(R1), R4 + MOVD 24(R1), R5 + MOVD 32(R1), R6 + SYSCALL $SYS_rt_sigaction + RETURN + +#ifdef GOARCH_power64le +// power64le doesn't need function descriptors +TEXT runtime·sigtramp(SB),NOSPLIT,$64 +#else +// function descriptor for the real sigtramp +TEXT runtime·sigtramp(SB),NOSPLIT,$-8 + DWORD $runtime·_sigtramp(SB) + DWORD $0 + DWORD $0 +TEXT runtime·_sigtramp(SB),NOSPLIT,$64 +#endif + // initialize essential registers (just in case) + BL runtime·reginit(SB) + + // check that g exists + CMP g, $0 + BNE 6(PC) + MOVD R3, 8(R1) + MOVD $runtime·badsignal(SB), R31 + MOVD R31, CTR + BL (CTR) + RETURN + + // save g + MOVD g, 40(R1) + MOVD g, R6 + + // g = m->gsignal + MOVD g_m(g), R7 + MOVD m_gsignal(R7), g + + MOVW R3, 8(R1) + MOVD R4, 16(R1) + MOVD R5, 24(R1) + MOVD R6, 32(R1) + + BL runtime·sighandler(SB) + + // restore g + MOVD 40(R1), g + + RETURN + +TEXT runtime·mmap(SB),NOSPLIT,$-8 + MOVD 8(R1), R3 + MOVD 16(R1), R4 + MOVW 24(R1), R5 + MOVW 28(R1), R6 + MOVW 32(R1), R7 + MOVW 36(R1), R8 + + SYSCALL $SYS_mmap + BVC 2(PC) + NEG R3, R3 + RETURN + +TEXT runtime·munmap(SB),NOSPLIT,$-8 + MOVD 8(R1), R3 + MOVD 16(R1), R4 + SYSCALL $SYS_munmap + BVC 2(PC) + MOVD R0, 0xf3(R0) + RETURN + +TEXT runtime·madvise(SB),NOSPLIT,$-8 + MOVD 8(R1), R3 + MOVD 16(R1), R4 + MOVD 24(R1), R5 + SYSCALL $SYS_madvise + // ignore failure - maybe pages are locked + RETURN + +// int64 futex(int32 *uaddr, int32 op, int32 val, +// struct timespec *timeout, int32 *uaddr2, int32 val2); +TEXT runtime·futex(SB),NOSPLIT,$-8 + MOVD 8(R1), R3 + MOVW 16(R1), R4 + MOVW 20(R1), R5 + MOVD 24(R1), R6 + MOVD 32(R1), R7 + MOVW 40(R1), R8 + SYSCALL $SYS_futex + RETURN + +// int64 clone(int32 flags, void *stack, M *mp, G *gp, void (*fn)(void)); +TEXT runtime·clone(SB),NOSPLIT,$-8 + MOVW flags+0(FP), R3 + MOVD stack+8(FP), R4 + + // Copy mp, gp, fn off parent stack for use by child. + // Careful: Linux system call clobbers ???. + MOVD mm+16(FP), R7 + MOVD gg+24(FP), R8 + MOVD fn+32(FP), R12 + + MOVD R7, -8(R4) + MOVD R8, -16(R4) + MOVD R12, -24(R4) + MOVD $1234, R7 + MOVD R7, -32(R4) + + SYSCALL $SYS_clone + + // In parent, return. + CMP R3, $0 + BEQ 2(PC) + RETURN + + // In child, on new stack. + // initialize essential registers + BL runtime·reginit(SB) + MOVD -32(R1), R7 + CMP R7, $1234 + BEQ 2(PC) + MOVD R0, 0(R0) + + // Initialize m->procid to Linux tid + SYSCALL $SYS_gettid + + MOVD -24(R1), R12 + MOVD -16(R1), R8 + MOVD -8(R1), R7 + + MOVD R3, m_procid(R7) + + // TODO: setup TLS. + + // In child, set up new stack + MOVD R7, g_m(R8) + MOVD R8, g + //CALL runtime·stackcheck(SB) + + // Call fn + MOVD R12, CTR + BL (CTR) + + // It shouldn't return. If it does, exit + MOVW $111, R3 + SYSCALL $SYS_exit_group + BR -2(PC) // keep exiting + +TEXT runtime·sigaltstack(SB),NOSPLIT,$-8 + MOVD new+0(FP), R3 + MOVD old+8(FP), R4 + SYSCALL $SYS_sigaltstack + BVC 2(PC) + MOVD R0, 0xf1(R0) // crash + RETURN + +TEXT runtime·osyield(SB),NOSPLIT,$-8 + SYSCALL $SYS_sched_yield + RETURN + +TEXT runtime·sched_getaffinity(SB),NOSPLIT,$-8 + MOVD 8(R1), R3 + MOVD 16(R1), R4 + MOVD 24(R1), R5 + SYSCALL $SYS_sched_getaffinity + RETURN + +// int32 runtime·epollcreate(int32 size); +TEXT runtime·epollcreate(SB),NOSPLIT,$-8 + MOVW 8(R1), R3 + SYSCALL $SYS_epoll_create + RETURN + +// int32 runtime·epollcreate1(int32 flags); +TEXT runtime·epollcreate1(SB),NOSPLIT,$-8 + MOVW 8(R1), R3 + SYSCALL $SYS_epoll_create1 + RETURN + +// int32 runtime·epollctl(int32 epfd, int32 op, int32 fd, EpollEvent *ev); +TEXT runtime·epollctl(SB),NOSPLIT,$-8 + MOVW 8(R1), R3 + MOVW 12(R1), R4 + MOVW 16(R1), R5 + MOVD 24(R1), R6 + SYSCALL $SYS_epoll_ctl + RETURN + +// int32 runtime·epollwait(int32 epfd, EpollEvent *ev, int32 nev, int32 timeout); +TEXT runtime·epollwait(SB),NOSPLIT,$-8 + MOVW 8(R1), R3 + MOVD 16(R1), R4 + MOVW 24(R1), R5 + MOVW 28(R1), R6 + SYSCALL $SYS_epoll_wait + RETURN + +// void runtime·closeonexec(int32 fd); +TEXT runtime·closeonexec(SB),NOSPLIT,$-8 + MOVW 8(R1), R3 // fd + MOVD $2, R4 // F_SETFD + MOVD $1, R5 // FD_CLOEXEC + SYSCALL $SYS_fcntl + RETURN diff --git a/src/pkg/runtime/sys_power64x.c b/src/pkg/runtime/sys_power64x.c new file mode 100644 index 0000000000..ed8900c45e --- /dev/null +++ b/src/pkg/runtime/sys_power64x.c @@ -0,0 +1,38 @@ +// 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. + +// +build power64 power64le + +#include "runtime.h" + +// adjust Gobuf as if it executed a call to fn with context ctxt +// and then did an immediate Gosave. +void +runtime·gostartcall(Gobuf *gobuf, void (*fn)(void), void *ctxt) +{ + if(gobuf->lr != 0) + runtime·throw("invalid use of gostartcall"); + gobuf->lr = gobuf->pc; + gobuf->pc = (uintptr)fn; + gobuf->ctxt = ctxt; +} + +// Called to rewind context saved during morestack back to beginning of function. +// To help us, the linker emits a jmp back to the beginning right after the +// call to morestack. We just have to decode and apply that jump. +void +runtime·rewindmorestack(Gobuf *gobuf) +{ + uint32 inst; + + inst = *(uint32*)gobuf->pc; + if((gobuf->pc&3) == 0 && (inst>>24) == 0x4b && (inst&3) == 0) { + runtime·printf("runtime: rewind pc=%p to pc=%p\n", gobuf->pc, gobuf->pc + ((int32)(inst<<8)>>8)); + gobuf->pc += (int32)(inst<<8)>>8; + return; + } + runtime·printf("runtime: pc=%p %x\n", gobuf->pc, inst); + runtime·throw("runtime: misuse of rewindmorestack"); +} +