diff --git a/src/runtime/arch1_ppc64.go b/src/runtime/arch1_ppc64.go index 01e2b70f952..6996d0fac00 100644 --- a/src/runtime/arch1_ppc64.go +++ b/src/runtime/arch1_ppc64.go @@ -8,7 +8,7 @@ const ( thechar = '9' _BigEndian = 1 _CacheLineSize = 64 - _RuntimeGogoBytes = 64 + _RuntimeGogoBytes = 72 _PhysPageSize = 65536 _PCQuantum = 4 _Int64Align = 8 diff --git a/src/runtime/arch1_ppc64le.go b/src/runtime/arch1_ppc64le.go index 6580732a371..7d5dac46a07 100644 --- a/src/runtime/arch1_ppc64le.go +++ b/src/runtime/arch1_ppc64le.go @@ -8,7 +8,7 @@ const ( thechar = '9' _BigEndian = 0 _CacheLineSize = 64 - _RuntimeGogoBytes = 64 + _RuntimeGogoBytes = 72 _PhysPageSize = 65536 _PCQuantum = 4 _Int64Align = 8 diff --git a/src/runtime/asm_ppc64x.s b/src/runtime/asm_ppc64x.s index 8ec051d5dd5..a2aba632e9b 100644 --- a/src/runtime/asm_ppc64x.s +++ b/src/runtime/asm_ppc64x.s @@ -10,6 +10,8 @@ #include "textflag.h" TEXT runtime·rt0_go(SB),NOSPLIT,$0 + // R1 = stack; R3 = argc; R4 = argv; R13 = C TLS base pointer + // initialize essential registers BL runtime·reginit(SB) @@ -102,6 +104,8 @@ TEXT runtime·gosave(SB), NOSPLIT, $-8-8 TEXT runtime·gogo(SB), NOSPLIT, $-8-8 MOVD buf+0(FP), R5 MOVD gobuf_g(R5), g // make sure g is not nil + BL runtime·save_g(SB) + MOVD 0(g), R4 MOVD gobuf_sp(R5), R1 MOVD gobuf_lr(R5), R31 @@ -133,6 +137,7 @@ TEXT runtime·mcall(SB), NOSPLIT, $-8-8 MOVD g, R3 MOVD g_m(g), R8 MOVD m_g0(R8), g + BL runtime·save_g(SB) CMP g, R3 BNE 2(PC) BR runtime·badmcall(SB) @@ -191,6 +196,7 @@ switch: // switch to g0 MOVD R5, g + BL runtime·save_g(SB) MOVD (g_sched+gobuf_sp)(g), R3 // make it look like mstart called systemstack on g0, to stop traceback SUB $8, R3 @@ -206,6 +212,7 @@ switch: // switch back to g MOVD g_m(g), R3 MOVD m_curg(R3), g + BL runtime·save_g(SB) MOVD (g_sched+gobuf_sp)(g), R1 MOVD R0, (g_sched+gobuf_sp)(g) RETURN @@ -259,6 +266,7 @@ TEXT runtime·morestack(SB),NOSPLIT,$-8-0 // Call newstack on m->g0's stack. MOVD m_g0(R7), g + BL runtime·save_g(SB) MOVD (g_sched+gobuf_sp)(g), R1 BL runtime·newstack(SB) diff --git a/src/runtime/rt0_linux_ppc64le.s b/src/runtime/rt0_linux_ppc64le.s index a3b3cea0b52..dda29ab3a09 100644 --- a/src/runtime/rt0_linux_ppc64le.s +++ b/src/runtime/rt0_linux_ppc64le.s @@ -6,6 +6,8 @@ TEXT _rt0_ppc64le_linux(SB),NOSPLIT,$0 TEXT _main<>(SB),NOSPLIT,$-8 MOVD 0(R1), R3 // argc ADD $8, R1, R4 // argv + MOVD $runtime·tls0(SB), R13 // TLS + ADD $0x7000, R13 BR main(SB) TEXT main(SB),NOSPLIT,$-8 diff --git a/src/runtime/tls_ppc64x.s b/src/runtime/tls_ppc64x.s new file mode 100644 index 00000000000..fa1f9ac6f05 --- /dev/null +++ b/src/runtime/tls_ppc64x.s @@ -0,0 +1,56 @@ +// 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 ppc64 ppc64le + +#include "go_asm.h" +#include "go_tls.h" +#include "funcdata.h" +#include "textflag.h" + +// We have to resort to TLS variable to save g (R30). +// One reason is that external code might trigger +// SIGSEGV, and our runtime.sigtramp don't even know we +// are in external code, and will continue to use R30, +// this might well result in another SIGSEGV. + +// save_g saves the g register into pthread-provided +// thread-local memory, so that we can call externally compiled +// ppc64 code that will overwrite this register. +// +// If !iscgo, this is a no-op. +TEXT runtime·save_g(SB),NOSPLIT,$-8-0 + MOVB runtime·iscgo(SB), R31 + CMP R31, $0 + BEQ nocgo + + // $runtime.tlsg(SB) is a special linker symbol. + // It is the offset from the start of TLS to our + // thread-local storage for g. + MOVD $runtime·tlsg(SB), R31 + ADD R13, R31 + // The actual TLS base is 0x7000 below R13 + SUB $0x7000, R31 + + // Store g in TLS + MOVD g, 0(R31) + +nocgo: + RET + +// load_g loads the g register from pthread-provided +// thread-local memory, for use after calling externally compiled +// ppc64 code that overwrote those registers. +// +// This is never called directly from C code (it doesn't have to +// follow the C ABI), but it may be called from a C context, where the +// usual Go registers aren't set up. +TEXT runtime·load_g(SB),NOSPLIT,$-8-0 + MOVD $runtime·tlsg(SB), R31 + // R13 is the C ABI TLS base pointer + 0x7000 + ADD R13, R31 + SUB $0x7000, R31 + + MOVD 0(R31), g + RET