]> Cypherpunks repositories - gostls13.git/commitdiff
[dev.power64] runtime: manually written parts for linux/power64 and linux/power64le...
authorShenghou Ma <minux@golang.org>
Tue, 12 Aug 2014 23:48:49 +0000 (19:48 -0400)
committerShenghou Ma <minux@golang.org>
Tue, 12 Aug 2014 23:48:49 +0000 (19:48 -0400)
LGTM=rsc
R=rsc, iant
CC=golang-codereviews
https://golang.org/cl/122430043

13 files changed:
src/pkg/runtime/arch_power64.h [new file with mode: 0644]
src/pkg/runtime/arch_power64le.h [new file with mode: 0644]
src/pkg/runtime/asm_power64x.s [new file with mode: 0644]
src/pkg/runtime/atomic_power64x.s [new file with mode: 0644]
src/pkg/runtime/memclr_power64x.s [new file with mode: 0644]
src/pkg/runtime/memmove_power64x.s [new file with mode: 0644]
src/pkg/runtime/rt0_linux_power64.s [new file with mode: 0644]
src/pkg/runtime/rt0_linux_power64le.s [new file with mode: 0644]
src/pkg/runtime/signal_linux_power64.h [new file with mode: 0644]
src/pkg/runtime/signal_linux_power64le.h [new file with mode: 0644]
src/pkg/runtime/signal_power64x.c [new file with mode: 0644]
src/pkg/runtime/sys_linux_power64x.s [new file with mode: 0644]
src/pkg/runtime/sys_power64x.c [new file with mode: 0644]

diff --git a/src/pkg/runtime/arch_power64.h b/src/pkg/runtime/arch_power64.h
new file mode 100644 (file)
index 0000000..3d5b494
--- /dev/null
@@ -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 (file)
index 0000000..d9241da
--- /dev/null
@@ -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 (file)
index 0000000..52640f4
--- /dev/null
@@ -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 (file)
index 0000000..c08590a
--- /dev/null
@@ -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 (file)
index 0000000..4a2437c
--- /dev/null
@@ -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 (file)
index 0000000..b618f0a
--- /dev/null
@@ -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 (file)
index 0000000..e944bcd
--- /dev/null
@@ -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 (file)
index 0000000..051815d
--- /dev/null
@@ -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 (file)
index 0000000..8406489
--- /dev/null
@@ -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 (file)
index 0000000..8406489
--- /dev/null
@@ -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 (file)
index 0000000..89c5c78
--- /dev/null
@@ -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 (file)
index 0000000..c0c41ef
--- /dev/null
@@ -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 (file)
index 0000000..ed8900c
--- /dev/null
@@ -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");
+}
+