1
0
mirror of https://github.com/golang/go synced 2024-11-19 01:04:40 -07:00

runtime: add s390x support (new files and lfstack_64bit.go modifications)

Change-Id: I51c0a332e3cbdab348564e5dcd27583e75e4b881
Reviewed-on: https://go-review.googlesource.com/20946
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
This commit is contained in:
Michael Munday 2016-03-18 19:09:39 -04:00 committed by Brad Fitzpatrick
parent 9658b7ef83
commit e6f36f0cd5
11 changed files with 2437 additions and 13 deletions

1130
src/runtime/asm_s390x.s Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,167 @@
// Copyright 2016 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package runtime
const (
_EINTR = 0x4
_EAGAIN = 0xb
_ENOMEM = 0xc
_PROT_NONE = 0x0
_PROT_READ = 0x1
_PROT_WRITE = 0x2
_PROT_EXEC = 0x4
_MAP_ANON = 0x20
_MAP_PRIVATE = 0x2
_MAP_FIXED = 0x10
_MADV_DONTNEED = 0x4
_MADV_HUGEPAGE = 0xe
_MADV_NOHUGEPAGE = 0xf
_SA_RESTART = 0x10000000
_SA_ONSTACK = 0x8000000
_SA_SIGINFO = 0x4
_SIGHUP = 0x1
_SIGINT = 0x2
_SIGQUIT = 0x3
_SIGILL = 0x4
_SIGTRAP = 0x5
_SIGABRT = 0x6
_SIGBUS = 0x7
_SIGFPE = 0x8
_SIGKILL = 0x9
_SIGUSR1 = 0xa
_SIGSEGV = 0xb
_SIGUSR2 = 0xc
_SIGPIPE = 0xd
_SIGALRM = 0xe
_SIGSTKFLT = 0x10
_SIGCHLD = 0x11
_SIGCONT = 0x12
_SIGSTOP = 0x13
_SIGTSTP = 0x14
_SIGTTIN = 0x15
_SIGTTOU = 0x16
_SIGURG = 0x17
_SIGXCPU = 0x18
_SIGXFSZ = 0x19
_SIGVTALRM = 0x1a
_SIGPROF = 0x1b
_SIGWINCH = 0x1c
_SIGIO = 0x1d
_SIGPWR = 0x1e
_SIGSYS = 0x1f
_FPE_INTDIV = 0x1
_FPE_INTOVF = 0x2
_FPE_FLTDIV = 0x3
_FPE_FLTOVF = 0x4
_FPE_FLTUND = 0x5
_FPE_FLTRES = 0x6
_FPE_FLTINV = 0x7
_FPE_FLTSUB = 0x8
_BUS_ADRALN = 0x1
_BUS_ADRERR = 0x2
_BUS_OBJERR = 0x3
_SEGV_MAPERR = 0x1
_SEGV_ACCERR = 0x2
_ITIMER_REAL = 0x0
_ITIMER_VIRTUAL = 0x1
_ITIMER_PROF = 0x2
_EPOLLIN = 0x1
_EPOLLOUT = 0x4
_EPOLLERR = 0x8
_EPOLLHUP = 0x10
_EPOLLRDHUP = 0x2000
_EPOLLET = 0x80000000
_EPOLL_CLOEXEC = 0x80000
_EPOLL_CTL_ADD = 0x1
_EPOLL_CTL_DEL = 0x2
_EPOLL_CTL_MOD = 0x3
)
type timespec struct {
tv_sec int64
tv_nsec int64
}
func (ts *timespec) set_sec(x int64) {
ts.tv_sec = x
}
func (ts *timespec) set_nsec(x int32) {
ts.tv_nsec = int64(x)
}
type timeval struct {
tv_sec int64
tv_usec int64
}
func (tv *timeval) set_usec(x int32) {
tv.tv_usec = int64(x)
}
type sigactiont struct {
sa_handler uintptr
sa_flags uint64
sa_restorer uintptr
sa_mask uint64
}
type siginfo struct {
si_signo int32
si_errno int32
si_code int32
// below here is a union; si_addr is the only field we use
si_addr uint64
}
type itimerval struct {
it_interval timeval
it_value timeval
}
type epollevent struct {
events uint32
pad_cgo_0 [4]byte
data [8]byte // unaligned uintptr
}
const (
_O_RDONLY = 0x0
_O_CLOEXEC = 0x80000
_SA_RESTORER = 0
)
type sigaltstackt struct {
ss_sp *byte
ss_flags int32
ss_size uintptr
}
type sigcontext struct {
psw_mask uint64
psw_addr uint64
gregs [16]uint64
aregs [16]uint32
fpc uint32
fpregs [16]uint64
}
type ucontext struct {
uc_flags uint64
uc_link *ucontext
uc_stack sigaltstackt
uc_mcontext sigcontext
uc_sigmask uint64
}

View File

@ -2,26 +2,32 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build arm64 mips64 mips64le ppc64 ppc64le
// +build arm64 mips64 mips64le ppc64 ppc64le s390x
package runtime
import "unsafe"
// On ppc64, Linux limits the user address space to 46 bits (see
// TASK_SIZE_USER64 in the Linux kernel). This has grown over time,
// so here we allow 48 bit addresses.
//
// On mips64, Linux limits the user address space to 40 bits (see
// TASK_SIZE64 in the Linux kernel). This has grown over time,
// so here we allow 48 bit addresses.
//
// In addition to the 16 bits taken from the top, we can take 3 from the
// bottom, because node must be pointer-aligned, giving a total of 19 bits
// of count.
const (
// addrBits is the number of bits needed to represent a virtual address.
//
// In Linux the user address space for each architecture is limited as
// follows (taken from the processor.h file for the architecture):
//
// Architecture Name Maximum Value (exclusive)
// ---------------------------------------------------------------------
// arm64 TASK_SIZE_64 Depends on configuration.
// ppc64{,le} TASK_SIZE_USER64 0x400000000000UL (46 bit addresses)
// mips64{,le} TASK_SIZE64 0x010000000000UL (40 bit addresses)
// s390x TASK_SIZE 0x020000000000UL (41 bit addresses)
//
// These values may increase over time.
addrBits = 48
cntBits = 64 - addrBits + 3
// In addition to the 16 bits taken from the top, we can take 3 from the
// bottom, because node must be pointer-aligned, giving a total of 19 bits
// of count.
cntBits = 64 - addrBits + 3
)
func lfstackPack(node *lfnode, cnt uintptr) uint64 {

122
src/runtime/memclr_s390x.s Normal file
View File

@ -0,0 +1,122 @@
// Copyright 2016 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
#include "textflag.h"
// void runtime·memclr(void*, uintptr)
TEXT runtime·memclr(SB),NOSPLIT|NOFRAME,$0-16
MOVD ptr+0(FP), R4
MOVD n+8(FP), R5
start:
CMPBLE R5, $3, clear0to3
CMPBLE R5, $7, clear4to7
CMPBLE R5, $11, clear8to11
CMPBLE R5, $15, clear12to15
CMP R5, $32
BGE clearmt32
MOVD R0, 0(R4)
MOVD R0, 8(R4)
ADD $16, R4
SUB $16, R5
BR start
clear0to3:
CMPBEQ R5, $0, done
CMPBNE R5, $1, clear2
MOVB R0, 0(R4)
RET
clear2:
CMPBNE R5, $2, clear3
MOVH R0, 0(R4)
RET
clear3:
MOVH R0, 0(R4)
MOVB R0, 2(R4)
RET
clear4to7:
CMPBNE R5, $4, clear5
MOVW R0, 0(R4)
RET
clear5:
CMPBNE R5, $5, clear6
MOVW R0, 0(R4)
MOVB R0, 4(R4)
RET
clear6:
CMPBNE R5, $6, clear7
MOVW R0, 0(R4)
MOVH R0, 4(R4)
RET
clear7:
MOVW R0, 0(R4)
MOVH R0, 4(R4)
MOVB R0, 6(R4)
RET
clear8to11:
CMPBNE R5, $8, clear9
MOVD R0, 0(R4)
RET
clear9:
CMPBNE R5, $9, clear10
MOVD R0, 0(R4)
MOVB R0, 8(R4)
RET
clear10:
CMPBNE R5, $10, clear11
MOVD R0, 0(R4)
MOVH R0, 8(R4)
RET
clear11:
MOVD R0, 0(R4)
MOVH R0, 8(R4)
MOVB R0, 10(R4)
RET
clear12to15:
CMPBNE R5, $12, clear13
MOVD R0, 0(R4)
MOVW R0, 8(R4)
RET
clear13:
CMPBNE R5, $13, clear14
MOVD R0, 0(R4)
MOVW R0, 8(R4)
MOVB R0, 12(R4)
RET
clear14:
CMPBNE R5, $14, clear15
MOVD R0, 0(R4)
MOVW R0, 8(R4)
MOVH R0, 12(R4)
RET
clear15:
MOVD R0, 0(R4)
MOVW R0, 8(R4)
MOVH R0, 12(R4)
MOVB R0, 14(R4)
RET
clearmt32:
CMP R5, $256
BLT clearlt256
XC $256, 0(R4), 0(R4)
ADD $256, R4
ADD $-256, R5
BR clearmt32
clearlt256:
CMPBEQ R5, $0, done
ADD $-1, R5
EXRL $runtime·memclr_s390x_exrl_xc(SB), R5
done:
RET
// DO NOT CALL - target for exrl (execute relative long) instruction.
TEXT runtime·memclr_s390x_exrl_xc(SB),NOSPLIT|NOFRAME,$0-0
XC $1, 0(R4), 0(R4)
MOVD R0, 0(R0)
RET

189
src/runtime/memmove_s390x.s Normal file
View File

@ -0,0 +1,189 @@
// Copyright 2016 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
#include "textflag.h"
// void runtime·memmove(void*, void*, uintptr)
TEXT runtime·memmove(SB),NOSPLIT|NOFRAME,$0-24
MOVD to+0(FP), R6
MOVD from+8(FP), R4
MOVD n+16(FP), R5
CMPBEQ R6, R4, done
start:
CMPBLE R5, $3, move0to3
CMPBLE R5, $7, move4to7
CMPBLE R5, $11, move8to11
CMPBLE R5, $15, move12to15
CMPBNE R5, $16, movemt16
MOVD 0(R4), R7
MOVD 8(R4), R8
MOVD R7, 0(R6)
MOVD R8, 8(R6)
RET
movemt16:
CMPBGT R4, R6, forwards
ADD R5, R4, R7
CMPBLE R7, R6, forwards
ADD R5, R6, R8
backwards:
MOVD -8(R7), R3
MOVD R3, -8(R8)
MOVD -16(R7), R3
MOVD R3, -16(R8)
ADD $-16, R5
ADD $-16, R7
ADD $-16, R8
CMP R5, $16
BGE backwards
BR start
forwards:
CMPBGT R5, $64, forwards_fast
MOVD 0(R4), R3
MOVD R3, 0(R6)
MOVD 8(R4), R3
MOVD R3, 8(R6)
ADD $16, R4
ADD $16, R6
ADD $-16, R5
CMP R5, $16
BGE forwards
BR start
forwards_fast:
CMP R5, $256
BLE forwards_small
MVC $256, 0(R4), 0(R6)
ADD $256, R4
ADD $256, R6
ADD $-256, R5
BR forwards_fast
forwards_small:
CMPBEQ R5, $0, done
ADD $-1, R5
EXRL $runtime·memmove_s390x_exrl_mvc(SB), R5
RET
move0to3:
CMPBEQ R5, $0, done
move1:
CMPBNE R5, $1, move2
MOVB 0(R4), R3
MOVB R3, 0(R6)
RET
move2:
CMPBNE R5, $2, move3
MOVH 0(R4), R3
MOVH R3, 0(R6)
RET
move3:
MOVH 0(R4), R3
MOVB 2(R4), R7
MOVH R3, 0(R6)
MOVB R7, 2(R6)
RET
move4to7:
CMPBNE R5, $4, move5
MOVW 0(R4), R3
MOVW R3, 0(R6)
RET
move5:
CMPBNE R5, $5, move6
MOVW 0(R4), R3
MOVB 4(R4), R7
MOVW R3, 0(R6)
MOVB R7, 4(R6)
RET
move6:
CMPBNE R5, $6, move7
MOVW 0(R4), R3
MOVH 4(R4), R7
MOVW R3, 0(R6)
MOVH R7, 4(R6)
RET
move7:
MOVW 0(R4), R3
MOVH 4(R4), R7
MOVB 6(R4), R8
MOVW R3, 0(R6)
MOVH R7, 4(R6)
MOVB R8, 6(R6)
RET
move8to11:
CMPBNE R5, $8, move9
MOVD 0(R4), R3
MOVD R3, 0(R6)
RET
move9:
CMPBNE R5, $9, move10
MOVD 0(R4), R3
MOVB 8(R4), R7
MOVD R3, 0(R6)
MOVB R7, 8(R6)
RET
move10:
CMPBNE R5, $10, move11
MOVD 0(R4), R3
MOVH 8(R4), R7
MOVD R3, 0(R6)
MOVH R7, 8(R6)
RET
move11:
MOVD 0(R4), R3
MOVH 8(R4), R7
MOVB 10(R4), R8
MOVD R3, 0(R6)
MOVH R7, 8(R6)
MOVB R8, 10(R6)
RET
move12to15:
CMPBNE R5, $12, move13
MOVD 0(R4), R3
MOVW 8(R4), R7
MOVD R3, 0(R6)
MOVW R7, 8(R6)
RET
move13:
CMPBNE R5, $13, move14
MOVD 0(R4), R3
MOVW 8(R4), R7
MOVB 12(R4), R8
MOVD R3, 0(R6)
MOVW R7, 8(R6)
MOVB R8, 12(R6)
RET
move14:
CMPBNE R5, $14, move15
MOVD 0(R4), R3
MOVW 8(R4), R7
MOVH 12(R4), R8
MOVD R3, 0(R6)
MOVW R7, 8(R6)
MOVH R8, 12(R6)
RET
move15:
MOVD 0(R4), R3
MOVW 8(R4), R7
MOVH 12(R4), R8
MOVB 14(R4), R10
MOVD R3, 0(R6)
MOVW R7, 8(R6)
MOVH R8, 12(R6)
MOVB R10, 14(R6)
done:
RET
// DO NOT CALL - target for exrl (execute relative long) instruction.
TEXT runtime·memmove_s390x_exrl_mvc(SB),NOSPLIT|NOFRAME,$0-0
MVC $1, 0(R4), 0(R6)
MOVD R0, 0(R0)
RET

View File

@ -0,0 +1,46 @@
// Copyright 2016 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package runtime
const (
_SS_DISABLE = 2
_NSIG = 65
_SI_USER = 0
_SIG_BLOCK = 0
_SIG_UNBLOCK = 1
_SIG_SETMASK = 2
_RLIMIT_AS = 9
)
type sigset uint64
type rlimit struct {
rlim_cur uintptr
rlim_max uintptr
}
var sigset_all = sigset(^uint64(0))
func sigaddset(mask *sigset, i int) {
if i > 64 {
throw("unexpected signal greater than 64")
}
*mask |= 1 << (uint(i) - 1)
}
func sigdelset(mask *sigset, i int) {
if i > 64 {
throw("unexpected signal greater than 64")
}
*mask &^= 1 << (uint(i) - 1)
}
func sigfillset(mask *uint64) {
*mask = ^uint64(0)
}
func sigcopyset(mask *sigset, m sigmask) {
*mask = sigset(uint64(m[0]) | uint64(m[1])<<32)
}

View File

@ -0,0 +1,20 @@
// Copyright 2016 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
#include "textflag.h"
TEXT _rt0_s390x_linux(SB),NOSPLIT|NOFRAME,$0
// In a statically linked binary, the stack contains argc,
// argv as argc string pointers followed by a NULL, envv as a
// sequence of string pointers followed by a NULL, and auxv.
// There is no TLS base pointer.
//
// TODO: Support dynamic linking entry point
MOVD 0(R15), R2 // argc
ADD $8, R15, R3 // argv
BR main(SB)
TEXT main(SB),NOSPLIT|NOFRAME,$0
MOVD $runtime·rt0_go(SB), R11
BR R11

View File

@ -0,0 +1,208 @@
// Copyright 2016 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package runtime
import (
"runtime/internal/sys"
"unsafe"
)
type sigctxt struct {
info *siginfo
ctxt unsafe.Pointer
}
func (c *sigctxt) regs() *sigcontext {
return (*sigcontext)(unsafe.Pointer(&(*ucontext)(c.ctxt).uc_mcontext))
}
func (c *sigctxt) r0() uint64 { return c.regs().gregs[0] }
func (c *sigctxt) r1() uint64 { return c.regs().gregs[1] }
func (c *sigctxt) r2() uint64 { return c.regs().gregs[2] }
func (c *sigctxt) r3() uint64 { return c.regs().gregs[3] }
func (c *sigctxt) r4() uint64 { return c.regs().gregs[4] }
func (c *sigctxt) r5() uint64 { return c.regs().gregs[5] }
func (c *sigctxt) r6() uint64 { return c.regs().gregs[6] }
func (c *sigctxt) r7() uint64 { return c.regs().gregs[7] }
func (c *sigctxt) r8() uint64 { return c.regs().gregs[8] }
func (c *sigctxt) r9() uint64 { return c.regs().gregs[9] }
func (c *sigctxt) r10() uint64 { return c.regs().gregs[10] }
func (c *sigctxt) r11() uint64 { return c.regs().gregs[11] }
func (c *sigctxt) r12() uint64 { return c.regs().gregs[12] }
func (c *sigctxt) r13() uint64 { return c.regs().gregs[13] }
func (c *sigctxt) r14() uint64 { return c.regs().gregs[14] }
func (c *sigctxt) r15() uint64 { return c.regs().gregs[15] }
func (c *sigctxt) link() uint64 { return c.regs().gregs[14] }
func (c *sigctxt) sp() uint64 { return c.regs().gregs[15] }
func (c *sigctxt) pc() uint64 { return c.regs().psw_addr }
func (c *sigctxt) sigcode() uint32 { return uint32(c.info.si_code) }
func (c *sigctxt) sigaddr() uint64 { return c.info.si_addr }
func (c *sigctxt) set_r0(x uint64) { c.regs().gregs[0] = x }
func (c *sigctxt) set_r13(x uint64) { c.regs().gregs[13] = x }
func (c *sigctxt) set_link(x uint64) { c.regs().gregs[14] = x }
func (c *sigctxt) set_sp(x uint64) { c.regs().gregs[15] = x }
func (c *sigctxt) set_pc(x uint64) { c.regs().psw_addr = x }
func (c *sigctxt) set_sigcode(x uint32) { c.info.si_code = int32(x) }
func (c *sigctxt) set_sigaddr(x uint64) {
*(*uintptr)(add(unsafe.Pointer(c.info), 2*sys.PtrSize)) = uintptr(x)
}
func dumpregs(c *sigctxt) {
print("r0 ", hex(c.r0()), "\t")
print("r1 ", hex(c.r1()), "\n")
print("r2 ", hex(c.r2()), "\t")
print("r3 ", hex(c.r3()), "\n")
print("r4 ", hex(c.r4()), "\t")
print("r5 ", hex(c.r5()), "\n")
print("r6 ", hex(c.r6()), "\t")
print("r7 ", hex(c.r7()), "\n")
print("r8 ", hex(c.r8()), "\t")
print("r9 ", hex(c.r9()), "\n")
print("r10 ", hex(c.r10()), "\t")
print("r11 ", hex(c.r11()), "\n")
print("r12 ", hex(c.r12()), "\t")
print("r13 ", hex(c.r13()), "\n")
print("r14 ", hex(c.r14()), "\t")
print("r15 ", hex(c.r15()), "\n")
print("pc ", hex(c.pc()), "\t")
print("link ", hex(c.link()), "\n")
}
var crashing int32
// May run during STW, so write barriers are not allowed.
//
//go:nowritebarrierrec
func sighandler(sig uint32, info *siginfo, ctxt unsafe.Pointer, gp *g) {
_g_ := getg()
c := &sigctxt{info, ctxt}
if sig == _SIGPROF {
sigprof(uintptr(c.pc()), uintptr(c.sp()), uintptr(c.link()), gp, _g_.m)
return
}
flags := int32(_SigThrow)
if sig < uint32(len(sigtable)) {
flags = sigtable[sig].flags
}
if c.sigcode() != _SI_USER && flags&_SigPanic != 0 {
// 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 = uintptr(c.sigcode())
gp.sigcode1 = uintptr(c.sigaddr())
gp.sigpc = uintptr(c.pc())
// 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.
sp := c.sp() - sys.MinFrameSize
c.set_sp(sp)
*(*uint64)(unsafe.Pointer(uintptr(sp))) = c.link()
pc := uintptr(gp.sigpc)
// If we don't recognize the PC as code
// but we do recognize the link register as code,
// then assume this was a call to non-code and treat like
// pc == 0, to make unwinding show the context.
if pc != 0 && findfunc(pc) == nil && findfunc(uintptr(c.link())) != nil {
pc = 0
}
// 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 pc != 0 {
c.set_link(uint64(pc))
}
// In case we are panicking from external C code
c.set_r0(0)
c.set_r13(uint64(uintptr(unsafe.Pointer(gp))))
c.set_pc(uint64(funcPC(sigpanic)))
return
}
if c.sigcode() == _SI_USER || flags&_SigNotify != 0 {
if sigsend(sig) {
return
}
}
if c.sigcode() == _SI_USER && signal_ignored(sig) {
return
}
if flags&_SigKill != 0 {
dieFromSignal(int32(sig))
}
if flags&_SigThrow == 0 {
return
}
_g_.m.throwing = 1
_g_.m.caughtsig.set(gp)
if crashing == 0 {
startpanic()
}
if sig < uint32(len(sigtable)) {
print(sigtable[sig].name, "\n")
} else {
print("Signal ", sig, "\n")
}
print("PC=", hex(c.pc()), " m=", _g_.m.id, "\n")
if _g_.m.lockedg != nil && _g_.m.ncgo > 0 && gp == _g_.m.g0 {
print("signal arrived during cgo execution\n")
gp = _g_.m.lockedg
}
print("\n")
level, _, docrash := gotraceback()
if level > 0 {
goroutineheader(gp)
tracebacktrap(uintptr(c.pc()), uintptr(c.sp()), uintptr(c.link()), gp)
if crashing > 0 && gp != _g_.m.curg && _g_.m.curg != nil && readgstatus(_g_.m.curg)&^_Gscan == _Grunning {
// tracebackothers on original m skipped this one; trace it now.
goroutineheader(_g_.m.curg)
traceback(^uintptr(0), ^uintptr(0), 0, gp)
} else if crashing == 0 {
tracebackothers(gp)
print("\n")
}
dumpregs(c)
}
if docrash {
crashing++
if crashing < sched.mcount {
// There are other m's that need to dump their stacks.
// Relay SIGQUIT to the next m by sending it to the current process.
// All m's that have already received SIGQUIT have signal masks blocking
// receipt of any signals, so the SIGQUIT will go to an m that hasn't seen it yet.
// When the last m receives the SIGQUIT, it will fall through to the call to
// crash below. Just in case the relaying gets botched, each m involved in
// the relay sleeps for 5 seconds and then does the crash/exit itself.
// In expected operation, the last m has received the SIGQUIT and run
// crash/exit and the process is gone, all long before any of the
// 5-second sleeps have finished.
print("\n-----\n\n")
raiseproc(_SIGQUIT)
usleep(5 * 1000 * 1000)
}
crash()
}
exit(2)
}

View File

@ -0,0 +1,440 @@
// Copyright 2016 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// System calls and other system stuff for Linux s390x; see
// /usr/include/asm/unistd.h for the syscall number definitions.
#include "go_asm.h"
#include "go_tls.h"
#include "textflag.h"
#define SYS_exit 1
#define SYS_read 3
#define SYS_write 4
#define SYS_open 5
#define SYS_close 6
#define SYS_getpid 20
#define SYS_kill 37
#define SYS_fcntl 55
#define SYS_gettimeofday 78
#define SYS_mmap 90
#define SYS_munmap 91
#define SYS_setitimer 104
#define SYS_clone 120
#define SYS_select 142
#define SYS_sched_yield 158
#define SYS_rt_sigreturn 173
#define SYS_rt_sigaction 174
#define SYS_rt_sigprocmask 175
#define SYS_sigaltstack 186
#define SYS_ugetrlimit 191
#define SYS_madvise 219
#define SYS_mincore 218
#define SYS_gettid 236
#define SYS_tkill 237
#define SYS_futex 238
#define SYS_sched_getaffinity 240
#define SYS_exit_group 248
#define SYS_epoll_create 249
#define SYS_epoll_ctl 250
#define SYS_epoll_wait 251
#define SYS_clock_gettime 260
#define SYS_epoll_create1 327
TEXT runtime·exit(SB),NOSPLIT|NOFRAME,$0-4
MOVW code+0(FP), R2
MOVW $SYS_exit_group, R1
SYSCALL
RET
TEXT runtime·exit1(SB),NOSPLIT|NOFRAME,$0-4
MOVW code+0(FP), R2
MOVW $SYS_exit, R1
SYSCALL
RET
TEXT runtime·open(SB),NOSPLIT|NOFRAME,$0-20
MOVD name+0(FP), R2
MOVW mode+8(FP), R3
MOVW perm+12(FP), R4
MOVW $SYS_open, R1
SYSCALL
MOVD $-4095, R3
CMPUBLT R2, R3, 2(PC)
MOVW $-1, R2
MOVW R2, ret+16(FP)
RET
TEXT runtime·closefd(SB),NOSPLIT|NOFRAME,$0-12
MOVW fd+0(FP), R2
MOVW $SYS_close, R1
SYSCALL
MOVD $-4095, R3
CMPUBLT R2, R3, 2(PC)
MOVW $-1, R2
MOVW R2, ret+8(FP)
RET
TEXT runtime·write(SB),NOSPLIT|NOFRAME,$0-28
MOVD fd+0(FP), R2
MOVD p+8(FP), R3
MOVW n+16(FP), R4
MOVW $SYS_write, R1
SYSCALL
MOVD $-4095, R3
CMPUBLT R2, R3, 2(PC)
MOVW $-1, R2
MOVW R2, ret+24(FP)
RET
TEXT runtime·read(SB),NOSPLIT|NOFRAME,$0-28
MOVW fd+0(FP), R2
MOVD p+8(FP), R3
MOVW n+16(FP), R4
MOVW $SYS_read, R1
SYSCALL
MOVD $-4095, R3
CMPUBLT R2, R3, 2(PC)
MOVW $-1, R2
MOVW R2, ret+24(FP)
RET
TEXT runtime·getrlimit(SB),NOSPLIT|NOFRAME,$0-20
MOVW kind+0(FP), R2
MOVD limit+8(FP), R3
MOVW $SYS_ugetrlimit, R1
SYSCALL
MOVW R2, ret+16(FP)
RET
TEXT runtime·usleep(SB),NOSPLIT,$16-4
MOVW usec+0(FP), R2
MOVD R2, R4
MOVW $1000000, R3
DIVD R3, R2
MOVD R2, 8(R15)
MULLD R2, R3
SUB R3, R4
MOVD R4, 16(R15)
// select(0, 0, 0, 0, &tv)
MOVW $0, R2
MOVW $0, R3
MOVW $0, R4
MOVW $0, R5
ADD $8, R15, R6
MOVW $SYS_select, R1
SYSCALL
RET
TEXT runtime·gettid(SB),NOSPLIT,$0-4
MOVW $SYS_gettid, R1
SYSCALL
MOVW R2, ret+0(FP)
RET
TEXT runtime·raise(SB),NOSPLIT|NOFRAME,$0
MOVW $SYS_gettid, R1
SYSCALL
MOVW R2, R2 // arg 1 tid
MOVW sig+0(FP), R3 // arg 2
MOVW $SYS_tkill, R1
SYSCALL
RET
TEXT runtime·raiseproc(SB),NOSPLIT|NOFRAME,$0
MOVW $SYS_getpid, R1
SYSCALL
MOVW R2, R2 // arg 1 pid
MOVW sig+0(FP), R3 // arg 2
MOVW $SYS_kill, R1
SYSCALL
RET
TEXT runtime·setitimer(SB),NOSPLIT|NOFRAME,$0-24
MOVW mode+0(FP), R2
MOVD new+8(FP), R3
MOVD old+16(FP), R4
MOVW $SYS_setitimer, R1
SYSCALL
RET
TEXT runtime·mincore(SB),NOSPLIT|NOFRAME,$0-28
MOVD addr+0(FP), R2
MOVD n+8(FP), R3
MOVD dst+16(FP), R4
MOVW $SYS_mincore, R1
SYSCALL
MOVW R2, ret+24(FP)
RET
// func now() (sec int64, nsec int32)
TEXT time·now(SB),NOSPLIT,$16
MOVD $0(R15), R2
MOVD $0, R3
MOVW $SYS_gettimeofday, R1
SYSCALL
MOVD 0(R15), R2 // sec
MOVD 8(R15), R4 // usec
MOVD $1000, R3
MULLD R3, R4
MOVD R2, sec+0(FP)
MOVW R4, nsec+8(FP)
RET
TEXT runtime·nanotime(SB),NOSPLIT,$16
MOVW $1, R2 // CLOCK_MONOTONIC
MOVD $0(R15), R3
MOVW $SYS_clock_gettime, R1
SYSCALL
MOVD 0(R15), R2 // sec
MOVD 8(R15), R4 // nsec
// sec is in R2, nsec in R4
// return nsec in R2
MOVD $1000000000, R3
MULLD R3, R2
ADD R4, R2
MOVD R2, ret+0(FP)
RET
TEXT runtime·rtsigprocmask(SB),NOSPLIT|NOFRAME,$0-28
MOVW sig+0(FP), R2
MOVD new+8(FP), R3
MOVD old+16(FP), R4
MOVW size+24(FP), R5
MOVW $SYS_rt_sigprocmask, R1
SYSCALL
MOVD $-4095, R3
CMPUBLT R2, R3, 2(PC)
MOVD R0, 0(R0) // crash
RET
TEXT runtime·rt_sigaction(SB),NOSPLIT|NOFRAME,$0-36
MOVD sig+0(FP), R2
MOVD new+8(FP), R3
MOVD old+16(FP), R4
MOVD size+24(FP), R5
MOVW $SYS_rt_sigaction, R1
SYSCALL
MOVW R2, ret+32(FP)
RET
TEXT runtime·sigfwd(SB),NOSPLIT,$0-32
MOVW sig+8(FP), R2
MOVD info+16(FP), R3
MOVD ctx+24(FP), R4
MOVD fn+0(FP), R5
BL R5
RET
TEXT runtime·sigtramp(SB),NOSPLIT,$64
// initialize essential registers (just in case)
XOR R0, R0
// this might be called in external code context,
// where g is not set.
MOVB runtime·iscgo(SB), R6
CMPBEQ R6, $0, 2(PC)
BL runtime·load_g(SB)
MOVW R2, 8(R15)
MOVD R3, 16(R15)
MOVD R4, 24(R15)
MOVD $runtime·sigtrampgo(SB), R5
BL R5
RET
TEXT runtime·cgoSigtramp(SB),NOSPLIT,$0
BR runtime·sigtramp(SB)
// func mmap(addr unsafe.Pointer, n uintptr, prot, flags, fd int32, off uint32) unsafe.Pointer
TEXT runtime·mmap(SB),NOSPLIT,$48-40
MOVD addr+0(FP), R2
MOVD n+8(FP), R3
MOVW prot+16(FP), R4
MOVW flags+20(FP), R5
MOVW fd+24(FP), R6
MOVWZ off+28(FP), R7
// s390x uses old_mmap, so the arguments need to be placed into
// a struct and a pointer to the struct passed to mmap.
MOVD R2, addr-48(SP)
MOVD R3, n-40(SP)
MOVD R4, prot-32(SP)
MOVD R5, flags-24(SP)
MOVD R6, fd-16(SP)
MOVD R7, off-8(SP)
MOVD $addr-48(SP), R2
MOVW $SYS_mmap, R1
SYSCALL
MOVD $-4095, R3
CMPUBLT R2, R3, 2(PC)
NEG R2
MOVD R2, ret+32(FP)
RET
TEXT runtime·munmap(SB),NOSPLIT|NOFRAME,$0
MOVD addr+0(FP), R2
MOVD n+8(FP), R3
MOVW $SYS_munmap, R1
SYSCALL
MOVD $-4095, R3
CMPUBLT R2, R3, 2(PC)
MOVD R0, 0(R0) // crash
RET
TEXT runtime·madvise(SB),NOSPLIT|NOFRAME,$0
MOVD addr+0(FP), R2
MOVD n+8(FP), R3
MOVW flags+16(FP), R4
MOVW $SYS_madvise, R1
SYSCALL
// ignore failure - maybe pages are locked
RET
// int64 futex(int32 *uaddr, int32 op, int32 val,
// struct timespec *timeout, int32 *uaddr2, int32 val2);
TEXT runtime·futex(SB),NOSPLIT|NOFRAME,$0
MOVD addr+0(FP), R2
MOVW op+8(FP), R3
MOVW val+12(FP), R4
MOVD ts+16(FP), R5
MOVD addr2+24(FP), R6
MOVW val3+32(FP), R7
MOVW $SYS_futex, R1
SYSCALL
MOVW R2, ret+40(FP)
RET
// int32 clone(int32 flags, void *stk, M *mp, G *gp, void (*fn)(void));
TEXT runtime·clone(SB),NOSPLIT|NOFRAME,$0
MOVW flags+0(FP), R3
MOVD stk+8(FP), R2
// 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), R9
MOVD R7, -8(R2)
MOVD R8, -16(R2)
MOVD R9, -24(R2)
MOVD $1234, R7
MOVD R7, -32(R2)
SYSCALL $SYS_clone
// In parent, return.
CMPBEQ R2, $0, 3(PC)
MOVW R2, ret+40(FP)
RET
// In child, on new stack.
// initialize essential registers
XOR R0, R0
MOVD -32(R15), R7
CMP R7, $1234
BEQ 2(PC)
MOVD R0, 0(R0)
// Initialize m->procid to Linux tid
SYSCALL $SYS_gettid
MOVD -24(R15), R9 // fn
MOVD -16(R15), R8 // g
MOVD -8(R15), R7 // m
CMPBEQ R7, $0, nog
CMP R8, $0
BEQ nog
MOVD R2, m_procid(R7)
// In child, set up new stack
MOVD R7, g_m(R8)
MOVD R8, g
//CALL runtime·stackcheck(SB)
nog:
// Call fn
BL R9
// It shouldn't return. If it does, exit that thread.
MOVW $111, R2
MOVW $SYS_exit, R1
SYSCALL
BR -2(PC) // keep exiting
TEXT runtime·sigaltstack(SB),NOSPLIT|NOFRAME,$0
MOVD new+0(FP), R2
MOVD old+8(FP), R3
MOVW $SYS_sigaltstack, R1
SYSCALL
MOVD $-4095, R3
CMPUBLT R2, R3, 2(PC)
MOVD R0, 0(R0) // crash
RET
TEXT runtime·osyield(SB),NOSPLIT|NOFRAME,$0
MOVW $SYS_sched_yield, R1
SYSCALL
RET
TEXT runtime·sched_getaffinity(SB),NOSPLIT|NOFRAME,$0
MOVD pid+0(FP), R2
MOVD len+8(FP), R3
MOVD buf+16(FP), R4
MOVW $SYS_sched_getaffinity, R1
SYSCALL
MOVW R2, ret+24(FP)
RET
// int32 runtime·epollcreate(int32 size);
TEXT runtime·epollcreate(SB),NOSPLIT|NOFRAME,$0
MOVW size+0(FP), R2
MOVW $SYS_epoll_create, R1
SYSCALL
MOVW R2, ret+8(FP)
RET
// int32 runtime·epollcreate1(int32 flags);
TEXT runtime·epollcreate1(SB),NOSPLIT|NOFRAME,$0
MOVW flags+0(FP), R2
MOVW $SYS_epoll_create1, R1
SYSCALL
MOVW R2, ret+8(FP)
RET
// func epollctl(epfd, op, fd int32, ev *epollEvent) int
TEXT runtime·epollctl(SB),NOSPLIT|NOFRAME,$0
MOVW epfd+0(FP), R2
MOVW op+4(FP), R3
MOVW fd+8(FP), R4
MOVD ev+16(FP), R5
MOVW $SYS_epoll_ctl, R1
SYSCALL
MOVW R2, ret+24(FP)
RET
// int32 runtime·epollwait(int32 epfd, EpollEvent *ev, int32 nev, int32 timeout);
TEXT runtime·epollwait(SB),NOSPLIT|NOFRAME,$0
MOVW epfd+0(FP), R2
MOVD ev+8(FP), R3
MOVW nev+16(FP), R4
MOVW timeout+20(FP), R5
MOVW $SYS_epoll_wait, R1
SYSCALL
MOVW R2, ret+24(FP)
RET
// void runtime·closeonexec(int32 fd);
TEXT runtime·closeonexec(SB),NOSPLIT|NOFRAME,$0
MOVW fd+0(FP), R2 // fd
MOVD $2, R3 // F_SETFD
MOVD $1, R4 // FD_CLOEXEC
MOVW $SYS_fcntl, R1
SYSCALL
RET

45
src/runtime/sys_s390x.go Normal file
View File

@ -0,0 +1,45 @@
// Copyright 2016 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package runtime
import "unsafe"
// adjust Gobuf as if it executed a call to fn with context ctxt
// and then did an immediate Gosave.
func gostartcall(buf *gobuf, fn, ctxt unsafe.Pointer) {
if buf.lr != 0 {
throw("invalid use of gostartcall")
}
buf.lr = buf.pc
buf.pc = uintptr(fn)
buf.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.
func rewindmorestack(buf *gobuf) {
var inst uint64
if buf.pc&1 == 0 && buf.pc != 0 {
inst = *(*uint64)(unsafe.Pointer(buf.pc))
switch inst >> 48 {
case 0xa7f4: // BRC (branch relative on condition) instruction.
inst >>= 32
inst &= 0xFFFF
offset := int64(int16(inst))
offset <<= 1
buf.pc += uintptr(offset)
return
case 0xc0f4: // BRCL (branch relative on condition long) instruction.
inst >>= 16
inst = inst & 0xFFFFFFFF
inst = (inst << 1) & 0xFFFFFFFF
buf.pc += uintptr(int32(inst))
return
}
}
print("runtime: pc=", hex(buf.pc), " ", hex(inst), "\n")
throw("runtime: misuse of rewindmorestack")
}

51
src/runtime/tls_s390x.s Normal file
View File

@ -0,0 +1,51 @@
// Copyright 2016 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
#include "go_asm.h"
#include "go_tls.h"
#include "funcdata.h"
#include "textflag.h"
// We have to resort to TLS variable to save g (R13).
// 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 R13,
// 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
// s390x code that will overwrite this register.
//
// If !iscgo, this is a no-op.
//
// NOTE: setg_gcc<> assume this clobbers only R10 and R11.
TEXT runtime·save_g(SB),NOSPLIT|NOFRAME,$0-0
MOVB runtime·iscgo(SB), R10
CMPBEQ R10, $0, nocgo
MOVW AR0, R11
SLD $32, R11
MOVW AR1, R11
MOVD runtime·tls_g(SB), R10
MOVD g, 0(R10)(R11*1)
nocgo:
RET
// load_g loads the g register from pthread-provided
// thread-local memory, for use after calling externally compiled
// s390x 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.
//
// NOTE: _cgo_topofstack assumes this only clobbers g (R13), R10 and R11.
TEXT runtime·load_g(SB),NOSPLIT|NOFRAME,$0-0
MOVW AR0, R11
SLD $32, R11
MOVW AR1, R11
MOVD runtime·tls_g(SB), R10
MOVD 0(R10)(R11*1), g
RET
GLOBL runtime·tls_g+0(SB),TLSBSS,$8