Commit 846ee046 authored by Aram Hăvărneanu's avatar Aram Hăvărneanu

runtime: add support for linux/arm64

Change-Id: Ibda6a5bedaff57fd161d63fc04ad260931d34413
Reviewed-on: https://go-review.googlesource.com/7142Reviewed-by: default avatarRuss Cox <rsc@golang.org>
parent 5a0c322b
// Copyright 2011 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 (
thechar = '7'
_BigEndian = 0
_CacheLineSize = 32
_RuntimeGogoBytes = 64
_PhysPageSize = 4096
_PCQuantum = 4
_Int64Align = 8
hugePageSize = 0
)
// 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.
package runtime
type uintreg uint64
type intptr int64 // TODO(rsc): remove
This diff is collapsed.
// Copyright 2015 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"
//go:noescape
func xadd(ptr *uint32, delta int32) uint32
//go:noescape
func xadd64(ptr *uint64, delta int64) uint64
//go:noescape
func xchg(ptr *uint32, new uint32) uint32
//go:noescape
func xchg64(ptr *uint64, new uint64) uint64
// NO go:noescape annotation; see atomic_pointer.go.
func xchgp1(ptr unsafe.Pointer, new unsafe.Pointer) unsafe.Pointer
//go:noescape
func xchguintptr(ptr *uintptr, new uintptr) uintptr
//go:noescape
func atomicload(ptr *uint32) uint32
//go:noescape
func atomicload64(ptr *uint64) uint64
//go:noescape
func atomicloadp(ptr unsafe.Pointer) unsafe.Pointer
//go:nosplit
func atomicor8(addr *uint8, v uint8) {
// TODO(dfc) implement this in asm.
// Align down to 4 bytes and use 32-bit CAS.
uaddr := uintptr(unsafe.Pointer(addr))
addr32 := (*uint32)(unsafe.Pointer(uaddr &^ 3))
word := uint32(v) << ((uaddr & 3) * 8) // little endian
for {
old := *addr32
if cas(addr32, old, old|word) {
return
}
}
}
//go:noescape
func cas64(ptr *uint64, old, new uint64) bool
//go:noescape
func atomicstore(ptr *uint32, val uint32)
//go:noescape
func atomicstore64(ptr *uint64, val uint64)
// NO go:noescape annotation; see atomic_pointer.go.
func atomicstorep1(ptr unsafe.Pointer, val unsafe.Pointer)
// 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.
#include "textflag.h"
// uint32 runtime·atomicload(uint32 volatile* addr)
TEXT ·atomicload(SB),NOSPLIT,$-8-12
MOVD ptr+0(FP), R0
LDARW (R0), R0
MOVW R0, ret+8(FP)
RET
// uint64 runtime·atomicload64(uint64 volatile* addr)
TEXT ·atomicload64(SB),NOSPLIT,$-8-16
MOVD ptr+0(FP), R0
LDAR (R0), R0
MOVD R0, ret+8(FP)
RET
// void *runtime·atomicloadp(void *volatile *addr)
TEXT ·atomicloadp(SB),NOSPLIT,$-8-16
MOVD ptr+0(FP), R0
LDAR (R0), R0
MOVD R0, ret+8(FP)
RET
TEXT runtime·atomicstorep1(SB), NOSPLIT, $0-16
B runtime·atomicstore64(SB)
TEXT runtime·atomicstore(SB), NOSPLIT, $0-12
MOVD ptr+0(FP), R0
MOVW val+8(FP), R1
STLRW R1, (R0)
RET
TEXT runtime·atomicstore64(SB), NOSPLIT, $0-16
MOVD ptr+0(FP), R0
MOVD val+8(FP), R1
STLR R1, (R0)
RET
TEXT runtime·xchg(SB), NOSPLIT, $0-20
again:
MOVD ptr+0(FP), R0
MOVW new+8(FP), R1
LDAXRW (R0), R2
STLXRW R1, (R0), R3
CBNZ R3, again
MOVW R2, ret+16(FP)
RET
TEXT runtime·xchg64(SB), NOSPLIT, $0-24
again:
MOVD ptr+0(FP), R0
MOVD new+8(FP), R1
LDAXR (R0), R2
STLXR R1, (R0), R3
CBNZ R3, again
MOVD R2, ret+16(FP)
RET
// bool runtime·cas64(uint64 *ptr, uint64 old, uint64 new)
// Atomically:
// if(*val == *old){
// *val = new;
// return 1;
// } else {
// return 0;
// }
TEXT runtime·cas64(SB), NOSPLIT, $0-25
MOVD ptr+0(FP), R0
MOVD old+8(FP), R1
MOVD new+16(FP), R2
again:
LDAXR (R0), R3
CMP R1, R3
BNE ok
STLXR R2, (R0), R3
CBNZ R3, again
ok:
CSET EQ, R0
MOVB R0, ret+24(FP)
RET
// uint32 xadd(uint32 volatile *ptr, int32 delta)
// Atomically:
// *val += delta;
// return *val;
TEXT runtime·xadd(SB), NOSPLIT, $0-20
again:
MOVD ptr+0(FP), R0
MOVW delta+8(FP), R1
LDAXRW (R0), R2
ADDW R2, R1, R2
STLXRW R2, (R0), R3
CBNZ R3, again
MOVW R2, ret+16(FP)
RET
TEXT runtime·xadd64(SB), NOSPLIT, $0-24
again:
MOVD ptr+0(FP), R0
MOVD delta+8(FP), R1
LDAXR (R0), R2
ADD R2, R1, R2
STLXR R2, (R0), R3
CBNZ R3, again
MOVD R2, ret+16(FP)
RET
TEXT runtime·xchguintptr(SB), NOSPLIT, $0-24
B runtime·xchg64(SB)
......@@ -3,6 +3,7 @@
// license that can be found in the LICENSE file.
// +build !arm
// +build !arm64
package runtime
......
......@@ -7,6 +7,9 @@
#ifdef GOARCH_arm
#define JMP B
#endif
#ifdef GOARCH_arm64
#define JMP B
#endif
#ifdef GOARCH_ppc64
#define JMP BR
#endif
......
// Created by cgo -cdefs and converted (by hand) to Go
// ../cmd/cgo/cgo -cdefs defs_linux.go defs1_linux.go defs2_linux.go
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_RESTORER = 0x0 // Only used on intel
_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 uint32
data [8]byte // to match amd64
}
// Created by cgo -cdefs and then converted to Go by hand
// ../cmd/cgo/cgo -cdefs defs_linux.go defs1_linux.go defs2_linux.go
const (
_O_RDONLY = 0x0
_O_CLOEXEC = 0x80000
)
type usigset struct {
__val [16]uint64
}
type sigaltstackt struct {
ss_sp *byte
ss_flags int32
pad_cgo_0 [4]byte
ss_size uintptr
}
type sigcontext struct {
fault_address uint64
/* AArch64 registers */
regs [31]uint64
sp uint64
pc uint64
pstate uint64
_pad [8]byte // __attribute__((__aligned__(16)))
__reserved [4096]byte
}
type ucontext struct {
uc_flags uint64
uc_link *ucontext
uc_stack sigaltstackt
uc_sigmask uint64
_pad [(1024 - 64) / 8]byte
_pad2 [8]byte // sigcontext must be aligned to 16-byte
uc_mcontext sigcontext
}
......@@ -134,7 +134,7 @@ func infoBigStruct() []byte {
typeScalar, typeScalar, typeScalar, typeScalar, // t int; y uint16; u uint64
typePointer, typeDead, // i string
}
case "amd64", "ppc64", "ppc64le":
case "arm64", "amd64", "ppc64", "ppc64le":
return []byte{
typePointer, // q *int
typeScalar, typeScalar, typeScalar, // w byte; e [17]byte
......
......@@ -6,7 +6,7 @@
// xxhash: https://code.google.com/p/xxhash/
// cityhash: https://code.google.com/p/cityhash/
// +build amd64 amd64p32 ppc64 ppc64le
// +build amd64 amd64p32 arm64 ppc64 ppc64le
package runtime
......
// 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.
package runtime
import "unsafe"
// 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 = 48
cntBits = 64 - addrBits + 3
)
func lfstackPack(node *lfnode, cnt uintptr) uint64 {
return uint64(uintptr(unsafe.Pointer(node)))<<(64-addrBits) | uint64(cnt&(1<<cntBits-1))
}
func lfstackUnpack(val uint64) (node *lfnode, cnt uintptr) {
node = (*lfnode)(unsafe.Pointer(uintptr(val >> cntBits << 3)))
cnt = uintptr(val & (1<<cntBits - 1))
return
}
......@@ -253,12 +253,20 @@ func mallocinit() {
// but it hardly matters: e0 00 is not valid UTF-8 either.
//
// If this fails we fall back to the 32 bit memory mechanism
//
// However, on arm64, we ignore all this advice above and slam the
// allocation at 0x40 << 32 because when using 4k pages with 3-level
// translation buffers, the user address space is limited to 39 bits
arenaSize := round(_MaxMem, _PageSize)
bitmapSize = arenaSize / (ptrSize * 8 / 4)
spansSize = arenaSize / _PageSize * ptrSize
spansSize = round(spansSize, _PageSize)
for i := 0; i <= 0x7f; i++ {
p = uintptr(i)<<40 | uintptrMask&(0x00c0<<32)
if GOARCH == "arm64" {
p = uintptr(i)<<40 | uintptrMask&(0x0040<<32)
} else {
p = uintptr(i)<<40 | uintptrMask&(0x00c0<<32)
}
pSize = bitmapSize + spansSize + arenaSize + _PageSize
p = uintptr(sysReserve(unsafe.Pointer(p), pSize, &reserved))
if p != 0 {
......
// 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.
#include "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 $0, R4
BEQ done
ADD R3, R4, R4
MOVBU.P $0, 1(R3)
CMP R3, R4
BNE -2(PC)
done:
RET
// 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.
#include "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 $0, R5
BNE check
RET
check:
CMP R3, R4
BLT backward
ADD R3, R5
loop:
MOVBU.P 1(R4), R6
MOVBU.P R6, 1(R3)
CMP R3, R5
BNE loop
RET
backward:
ADD R5, R4
ADD R3, R5
loop1:
MOVBU.W -1(R4), R6
MOVBU.W R6, -1(R5)
CMP R3, R5
BNE loop1
RET
......@@ -289,10 +289,13 @@ func scanframeworker(frame *stkframe, unused unsafe.Pointer, gcw *gcWorkProducer
// Scan local variables if stack frame has been allocated.
size := frame.varp - frame.sp
var minsize uintptr
if thechar != '6' && thechar != '8' {
minsize = ptrSize
} else {
switch thechar {
case '6', '8':
minsize = 0
case '7':
minsize = spAlign
default:
minsize = ptrSize
}
if size > minsize {
stkmap := (*stackmap)(funcdata(f, _FUNCDATA_LocalsPointerMaps))
......
......@@ -4,7 +4,7 @@
// Routines that are implemented in assembly in asm_{amd64,386}.s
// +build arm ppc64 ppc64le
// +build arm arm64 ppc64 ppc64le
package runtime
......
// Copyright 2015 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 (
_AT_NULL = 0
_AT_RANDOM = 25 // introduced in 2.6.29
)
var randomNumber uint32
func cputicks() int64 {
// Currently cputicks() is used in blocking profiler and to seed fastrand1().
// nanotime() is a poor approximation of CPU ticks that is enough for the profiler.
// randomNumber provides better seeding of fastrand1.
return nanotime() + int64(randomNumber)
}
......@@ -10,7 +10,7 @@ package runtime
//uint32 runtime·panicking;
var paniclk mutex
const hasLinkRegister = GOARCH == "arm" || GOARCH == "ppc64" || GOARCH == "ppc64le"
const hasLinkRegister = GOARCH == "arm" || GOARCH == "arm64" || GOARCH == "ppc64" || GOARCH == "ppc64le"
// Unwind the stack after a deferred function calls recover
// after a panic. Then arrange to continue running as though
......
......@@ -2042,15 +2042,19 @@ func newproc1(fn *funcval, argp *uint8, narg int32, nret int32, callerpc uintptr
throw("newproc1: new g is not Gdead")
}
sp := newg.stack.hi
sp -= 4 * regSize // extra space in case of reads slightly beyond frame
sp -= uintptr(siz)
memmove(unsafe.Pointer(sp), unsafe.Pointer(argp), uintptr(narg))
totalSize := 4*regSize + uintptr(siz) // extra space in case of reads slightly beyond frame
if hasLinkRegister {
totalSize += ptrSize
}
totalSize += -totalSize & (spAlign - 1) // align to spAlign
sp := newg.stack.hi - totalSize
spArg := sp
if hasLinkRegister {
// caller's LR
sp -= ptrSize
*(*unsafe.Pointer)(unsafe.Pointer(sp)) = nil
spArg += ptrSize
}
memmove(unsafe.Pointer(spArg), unsafe.Pointer(argp), uintptr(narg))
memclr(unsafe.Pointer(&newg.sched), unsafe.Sizeof(newg.sched))
newg.sched.sp = sp
......
// Copyright 2015 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_arm64_linux(SB),NOSPLIT,$-8
MOVD 0(RSP), R0 // argc
ADD $8, RSP, R1 // argv
BL main(SB)
TEXT main(SB),NOSPLIT,$-8
MOVD $runtime·rt0_go(SB), R2
BL (R2)
exit:
MOVD $0, R0
MOVD $94, R8 // sys_exit
SVC
B exit
// 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
package runtime
import "unsafe"
func dumpregs(c *sigctxt) {
print("r0 ", hex(c.r0()), "\n")
print("r1 ", hex(c.r1()), "\n")
print("r2 ", hex(c.r2()), "\n")
print("r3 ", hex(c.r3()), "\n")
print("r4 ", hex(c.r4()), "\n")
print("r5 ", hex(c.r5()), "\n")
print("r6 ", hex(c.r6()), "\n")
print("r7 ", hex(c.r7()), "\n")
print("r8 ", hex(c.r8()), "\n")
print("r9 ", hex(c.r9()), "\n")
print("r10 ", hex(c.r10()), "\n")
print("r11 ", hex(c.r11()), "\n")
print("r12 ", hex(c.r12()), "\n")
print("r13 ", hex(c.r13()), "\n")
print("r14 ", hex(c.r14()), "\n")
print("r15 ", hex(c.r15()), "\n")
print("r16 ", hex(c.r16()), "\n")
print("r17 ", hex(c.r17()), "\n")
print("r18 ", hex(c.r18()), "\n")
print("r19 ", hex(c.r19()), "\n")
print("r20 ", hex(c.r20()), "\n")
print("r21 ", hex(c.r21()), "\n")
print("r22 ", hex(c.r22()), "\n")
print("r23 ", hex(c.r23()), "\n")
print("r24 ", hex(c.r24()), "\n")
print("r25 ", hex(c.r25()), "\n")
print("r26 ", hex(c.r26()), "\n")
print("r27 ", hex(c.r27()), "\n")
print("r28 ", hex(c.r28()), "\n")
print("r29 ", hex(c.r29()), "\n")
print("lr ", hex(c.lr()), "\n")
print("sp ", hex(c.sp()), "\n")
print("pc ", hex(c.pc()), "\n")
print("fault ", hex(c.fault()), "\n")
}
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.lr()), 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.fault())
gp.sigpc = uintptr(c.pc())
// We arrange lr, and pc to pretend the panicking
// function calls sigpanic directly.
// Always save LR to stack so that panics in leaf
// functions are correctly handled. This smashes
// the stack frame but we're not going back there
// anyway.
sp := c.sp() - spAlign // needs only sizeof uint64, but must align the stack
c.set_sp(sp)
*(*uint64)(unsafe.Pointer(uintptr(sp))) = c.lr()
// 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 {
c.set_lr(uint64(gp.sigpc))
}
// In case we are panicking from external C code
c.set_r28(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 flags&_SigKill != 0 {
exit(2)
}
if flags&_SigThrow == 0 {
return
}
_g_.m.throwing = 1
_g_.m.caughtsig = gp
startpanic()
if sig < uint32(len(sigtable)) {
print(sigtable[sig].name, "\n")
} else {
print("Signal ", sig, "\n")
}
print("PC=", hex(c.pc()), "\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")
var docrash bool
if gotraceback(&docrash) > 0 {
goroutineheader(gp)
tracebacktrap(uintptr(c.pc()), uintptr(c.sp()), uintptr(c.lr()), gp)
tracebackothers(gp)
print("\n")
dumpregs(c)
}
if docrash {
crash()
}
exit(2)
}
// Copyright 2015 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"
type sigctxt struct {
info *siginfo
ctxt unsafe.Pointer
}
func (c *sigctxt) regs() *sigcontext { return &(*ucontext)(c.ctxt).uc_mcontext }
func (c *sigctxt) r0() uint64 { return c.regs().regs[0] }
func (c *sigctxt) r1() uint64 { return c.regs().regs[1] }
func (c *sigctxt) r2() uint64 { return c.regs().regs[2] }
func (c *sigctxt) r3() uint64 { return c.regs().regs[3] }
func (c *sigctxt) r4() uint64 { return c.regs().regs[4] }
func (c *sigctxt) r5() uint64 { return c.regs().regs[5] }
func (c *sigctxt) r6() uint64 { return c.regs().regs[6] }
func (c *sigctxt) r7() uint64 { return c.regs().regs[7] }
func (c *sigctxt) r8() uint64 { return c.regs().regs[8] }
func (c *sigctxt) r9() uint64 { return c.regs().regs[9] }
func (c *sigctxt) r10() uint64 { return c.regs().regs[10] }
func (c *sigctxt) r11() uint64 { return c.regs().regs[11] }
func (c *sigctxt) r12() uint64 { return c.regs().regs[12] }
func (c *sigctxt) r13() uint64 { return c.regs().regs[13] }
func (c *sigctxt) r14() uint64 { return c.regs().regs[14] }
func (c *sigctxt) r15() uint64 { return c.regs().regs[15] }
func (c *sigctxt) r16() uint64 { return c.regs().regs[16] }
func (c *sigctxt) r17() uint64 { return c.regs().regs[17] }
func (c *sigctxt) r18() uint64 { return c.regs().regs[18] }
func (c *sigctxt) r19() uint64 { return c.regs().regs[19] }
func (c *sigctxt) r20() uint64 { return c.regs().regs[20] }
func (c *sigctxt) r21() uint64 { return c.regs().regs[21] }
func (c *sigctxt) r22() uint64 { return c.regs().regs[22] }
func (c *sigctxt) r23() uint64 { return c.regs().regs[23] }
func (c *sigctxt) r24() uint64 { return c.regs().regs[24] }
func (c *sigctxt) r25() uint64 { return c.regs().regs[25] }
func (c *sigctxt) r26() uint64 { return c.regs().regs[26] }
func (c *sigctxt) r27() uint64 { return c.regs().regs[27] }
func (c *sigctxt) r28() uint64 { return c.regs().regs[28] }
func (c *sigctxt) r29() uint64 { return c.regs().regs[29] }
func (c *sigctxt) lr() uint64 { return c.regs().regs[30] }
func (c *sigctxt) sp() uint64 { return c.regs().sp }
func (c *sigctxt) pc() uint64 { return c.regs().pc }
func (c *sigctxt) pstate() uint64 { return c.regs().pstate }
func (c *sigctxt) fault() uint64 { return c.regs().fault_address }
func (c *sigctxt) sigcode() uint64 { return uint64(c.info.si_code) }
func (c *sigctxt) sigaddr() uint64 { return c.info.si_addr }
func (c *sigctxt) set_pc(x uint64) { c.regs().pc = x }
func (c *sigctxt) set_sp(x uint64) { c.regs().sp = x }
func (c *sigctxt) set_lr(x uint64) { c.regs().regs[30] = x }
func (c *sigctxt) set_r28(x uint64) { c.regs().regs[28] = x }
func (c *sigctxt) set_sigaddr(x uint64) {
*(*uintptr)(add(unsafe.Pointer(c.info), 2*ptrSize)) = uintptr(x)
}
......@@ -439,10 +439,13 @@ func adjustframe(frame *stkframe, arg unsafe.Pointer) bool {
// Adjust local variables if stack frame has been allocated.
size := frame.varp - frame.sp
var minsize uintptr
if thechar != '6' && thechar != '8' {
minsize = ptrSize
} else {
switch thechar {
case '6', '8':
minsize = 0
case '7':
minsize = spAlign
default:
minsize = ptrSize
}
if size > minsize {
var bv bitvector
......
......@@ -8,8 +8,9 @@ import "unsafe"
// Declarations for runtime services implemented in C or assembly.
const ptrSize = 4 << (^uintptr(0) >> 63) // unsafe.Sizeof(uintptr(0)) but an ideal const
const regSize = 4 << (^uintreg(0) >> 63) // unsafe.Sizeof(uintreg(0)) but an ideal const
const ptrSize = 4 << (^uintptr(0) >> 63) // unsafe.Sizeof(uintptr(0)) but an ideal const
const regSize = 4 << (^uintreg(0) >> 63) // unsafe.Sizeof(uintreg(0)) but an ideal const
const spAlign = 1*(1-goarch_arm64) + 16*goarch_arm64 // SP alignment: 1 normally, 16 for ARM64
// Should be a built-in for unsafe.Pointer?
//go:nosplit
......
// Copyright 2013 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
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 uint32
if buf.pc&3 == 0 && buf.pc != 0 {
inst = *(*uint32)(unsafe.Pointer(buf.pc))
// section C3.2.6 Unconditional branch (immediate)
if inst>>26 == 0x05 {
buf.pc += uintptr(int32(inst<<6) >> 4)
return
}
}
print("runtime: pc=", hex(buf.pc), " ", hex(inst), "\n")
throw("runtime: misuse of rewindmorestack")
}
// 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.
//
// System calls and other sys.stuff for arm64, Linux
//
#include "go_asm.h"
#include "go_tls.h"
#include "textflag.h"
#define AT_FDCWD -100
#define SYS_exit 93
#define SYS_read 63
#define SYS_write 64
#define SYS_openat 56
#define SYS_close 57
#define SYS_fcntl 25
#define SYS_gettimeofday 169
#define SYS_pselect6 72
#define SYS_mmap 222
#define SYS_munmap 215
#define SYS_setitimer 103
#define SYS_clone 220
#define SYS_sched_yield 124
#define SYS_rt_sigreturn 139
#define SYS_rt_sigaction 134
#define SYS_rt_sigprocmask 135
#define SYS_sigaltstack 132
#define SYS_getrlimit 163
#define SYS_madvise 233
#define SYS_mincore 232
#define SYS_gettid 178
#define SYS_tkill 130
#define SYS_futex 98
#define SYS_sched_getaffinity 123
#define SYS_exit_group 94
#define SYS_epoll_create1 20
#define SYS_epoll_ctl 21
#define SYS_epoll_pwait 22
#define SYS_clock_gettime 113
TEXT runtime·exit(SB),NOSPLIT,$-8-4
MOVW code+0(FP), R0
MOVD $SYS_exit_group, R8
SVC
RET
TEXT runtime·exit1(SB),NOSPLIT,$-8-4
MOVW code+0(FP), R0
MOVD $SYS_exit, R8
SVC
RET
TEXT runtime·open(SB),NOSPLIT,$-8-20
MOVD $AT_FDCWD, R0
MOVD name+0(FP), R1
MOVW mode+8(FP), R2
MOVW perm+12(FP), R3
MOVD $SYS_openat, R8
SVC
CMN $4095, R0
BCC done
MOVW $-1, R0
done:
MOVW R0, ret+16(FP)
RET
TEXT runtime·close(SB),NOSPLIT,$-8-12
MOVW fd+0(FP), R0
MOVD $SYS_close, R8
SVC
BCC done
MOVW $-1, R0
done:
MOVW R0, ret+8(FP)
RET
TEXT runtime·write(SB),NOSPLIT,$-8-28
MOVD fd+0(FP), R0
MOVD p+8(FP), R1
MOVW n+16(FP), R2
MOVD $SYS_write, R8
SVC
BCC done
MOVW $-1, R0
done:
MOVW R0, ret+24(FP)
RET
TEXT runtime·read(SB),NOSPLIT,$-8-28
MOVW fd+0(FP), R0
MOVD p+8(FP), R1
MOVW n+16(FP), R2
MOVD $SYS_read, R8
SVC
BCC done
MOVW $-1, R0
done:
MOVW R0, ret+24(FP)
RET
TEXT runtime·getrlimit(SB),NOSPLIT,$-8-20
MOVW kind+0(FP), R0
MOVD limit+8(FP), R1
MOVD $SYS_getrlimit, R8
SVC
MOVW R0, ret+16(FP)
RET
TEXT runtime·usleep(SB),NOSPLIT,$16-4
MOVWU usec+0(FP), R3
MOVD R3, R5
MOVW $1000000, R4
UDIV R4, R3
MOVD R3, 8(RSP)
MUL R3, R4
SUB R4, R5
MOVW $1000, R4
MUL R4, R5
MOVD R5, 16(RSP)
// pselect6(0, 0, 0, 0, &ts, 0)
MOVD $0, R0
MOVD R0, R1
MOVD R0, R2
MOVD R0, R3
ADD $8, RSP, R4
MOVD R0, R5
MOVD $SYS_pselect6, R8
SVC
RET
TEXT runtime·raise(SB),NOSPLIT,$-8
MOVD $SYS_gettid, R8
SVC
MOVW R0, R0 // arg 1 tid
MOVW sig+0(FP), R1 // arg 2
MOVD $SYS_tkill, R8
SVC
RET
TEXT runtime·setitimer(SB),NOSPLIT,$-8-24
MOVW mode+0(FP), R0
MOVD new+8(FP), R1
MOVD old+16(FP), R2
MOVD $SYS_setitimer, R8
SVC
RET
TEXT runtime·mincore(SB),NOSPLIT,$-8-28
MOVD addr+0(FP), R0
MOVD n+8(FP), R1
MOVD dst+16(FP), R2
MOVD $SYS_mincore, R8
SVC
MOVW R0, ret+24(FP)
RET
// func now() (sec int64, nsec int32)
TEXT time·now(SB),NOSPLIT,$16-12
MOVD RSP, R0
MOVD $0, R1
MOVD $SYS_gettimeofday, R8
SVC
MOVD 0(RSP), R3 // sec
MOVD 8(RSP), R5 // usec
MOVD $1000, R4
MUL R4, R5
MOVD R3, sec+0(FP)
MOVW R5, nsec+8(FP)
RET
TEXT runtime·nanotime(SB),NOSPLIT,$16-8
MOVW $1, R0 // CLOCK_MONOTONIC
MOVD RSP, R1
MOVD $SYS_clock_gettime, R8
SVC
MOVD 0(RSP), R3 // sec
MOVD 8(RSP), R5 // nsec
// sec is in R3, nsec in R5
// return nsec in R3
MOVD $1000000000, R4
MUL R4, R3
ADD R5, R3
MOVD R3, ret+0(FP)
RET
TEXT runtime·rtsigprocmask(SB),NOSPLIT,$-8-28
MOVW sig+0(FP), R0
MOVD new+8(FP), R1
MOVD old+16(FP), R2
MOVW size+24(FP), R3
MOVD $SYS_rt_sigprocmask, R8
SVC
CMN $4095, R0
BCC done
MOVD $0, R0
MOVD R0, (R0) // crash
done:
RET
TEXT runtime·rt_sigaction(SB),NOSPLIT,$-8-36
MOVD sig+0(FP), R0
MOVD new+8(FP), R1
MOVD old+16(FP), R2
MOVD size+24(FP), R3
MOVD $SYS_rt_sigaction, R8
SVC
MOVW R0, ret+32(FP)
RET
TEXT runtime·sigtramp(SB),NOSPLIT,$64
// this might be called in external code context,
// where g is not set.
// first save R0, because runtime·load_g will clobber it
MOVW R0, 8(RSP)
// TODO(minux): iscgo & load_g
// check that g exists
CMP g, ZR
BNE ok
MOVD $runtime·badsignal(SB), R0
BL (R0)
RET
ok:
// save g
MOVD g, 40(RSP)
MOVD g, R6
// g = m->gsignal
MOVD g_m(g), R7
MOVD m_gsignal(R7), g
// R0 is already saved above
MOVD R1, 16(RSP)
MOVD R2, 24(RSP)
MOVD R6, 32(RSP)
BL runtime·sighandler(SB)
// restore g
MOVD 40(RSP), g
RET
TEXT runtime·mmap(SB),NOSPLIT,$-8
MOVD addr+0(FP), R0
MOVD n+8(FP), R1
MOVW prot+16(FP), R2
MOVW flags+20(FP), R3
MOVW fd+24(FP), R4
MOVW off+28(FP), R5
MOVD $SYS_mmap, R8
SVC
MOVD R0, ret+32(FP)
RET
TEXT runtime·munmap(SB),NOSPLIT,$-8
MOVD addr+0(FP), R0
MOVD n+8(FP), R1
MOVD $SYS_munmap, R8
SVC
CMN $4095, R0
BCC cool
MOVD R0, 0xf0(R0)
cool:
RET
TEXT runtime·madvise(SB),NOSPLIT,$-8
MOVD addr+0(FP), R0
MOVD n+8(FP), R1
MOVW flags+16(FP), R2
MOVD $SYS_madvise, R8
SVC
// 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,$-8
MOVD addr+0(FP), R0
MOVW op+8(FP), R1
MOVW val+12(FP), R2
MOVD ts+16(FP), R3
MOVD addr2+24(FP), R4
MOVW val3+32(FP), R5
MOVD $SYS_futex, R8
SVC
MOVW R0, ret+40(FP)
RET
// int64 clone(int32 flags, void *stk, M *mp, G *gp, void (*fn)(void));
TEXT runtime·clone(SB),NOSPLIT,$-8
MOVW flags+0(FP), R0
MOVD stk+8(FP), R1
// Copy mp, gp, fn off parent stack for use by child.
MOVD mm+16(FP), R10
MOVD gg+24(FP), R11
MOVD fn+32(FP), R12
MOVD R10, -8(R1)
MOVD R11, -16(R1)
MOVD R12, -24(R1)
MOVD $1234, R10
MOVD R10, -32(R1)
MOVD $SYS_clone, R8
SVC
// In parent, return.
CMP ZR, R0
BEQ child
MOVW R0, ret+40(FP)
RET
child:
// In child, on new stack.
MOVD -32(RSP), R10
MOVD $1234, R0
CMP R0, R10
BEQ good
MOVD $0, R0
MOVD R0, (R0) // crash
// Initialize m->procid to Linux tid
good:
MOVD $SYS_gettid, R8
SVC
MOVD -24(RSP), R12
MOVD -16(RSP), R11
MOVD -8(RSP), R10
MOVD R0, m_procid(R10)
// TODO: setup TLS.
// In child, set up new stack
MOVD R10, g_m(R11)
MOVD R11, g
//CALL runtime·stackcheck(SB)
// Call fn
MOVD R12, R0
BL (R0)
// It shouldn't return. If it does, exit
MOVW $111, R0
again:
MOVD $SYS_exit_group, R8
SVC
B again // keep exiting
TEXT runtime·sigaltstack(SB),NOSPLIT,$-8
MOVD new+0(FP), R0
MOVD old+8(FP), R1
MOVD $SYS_sigaltstack, R8
SVC
CMN $4095, R0
BCC ok
MOVD $0, R0
MOVD R0, (R0) // crash
ok:
RET
TEXT runtime·osyield(SB),NOSPLIT,$-8
MOVD $SYS_sched_yield, R8
SVC
RET
TEXT runtime·sched_getaffinity(SB),NOSPLIT,$-8
MOVD pid+0(FP), R0
MOVD len+8(FP), R1
MOVD buf+16(FP), R2
MOVD $SYS_sched_getaffinity, R8
SVC
MOVW R0, ret+24(FP)
RET
// int32 runtime·epollcreate(int32 size);
TEXT runtime·epollcreate(SB),NOSPLIT,$-8
MOVW $0, R0
MOVD $SYS_epoll_create1, R8
SVC
MOVW R0, ret+8(FP)
RET
// int32 runtime·epollcreate1(int32 flags);
TEXT runtime·epollcreate1(SB),NOSPLIT,$-8
MOVW flags+0(FP), R0
MOVD $SYS_epoll_create1, R8
SVC
MOVW R0, ret+8(FP)
RET
// func epollctl(epfd, op, fd int32, ev *epollEvent) int
TEXT runtime·epollctl(SB),NOSPLIT,$-8
MOVW epfd+0(FP), R0
MOVW op+4(FP), R1
MOVW fd+8(FP), R2
MOVD ev+16(FP), R3
MOVD $SYS_epoll_ctl, R8
SVC
MOVW R0, ret+24(FP)
RET
// int32 runtime·epollwait(int32 epfd, EpollEvent *ev, int32 nev, int32 timeout);
TEXT runtime·epollwait(SB),NOSPLIT,$-8
MOVW epfd+0(FP), R0
MOVD ev+8(FP), R1
MOVW nev+16(FP), R2
MOVW timeout+20(FP), R3
MOVD $0, R4
MOVD $SYS_epoll_pwait, R8
SVC
MOVW R0, ret+24(FP)
RET
// void runtime·closeonexec(int32 fd);
TEXT runtime·closeonexec(SB),NOSPLIT,$-8
MOVW fd+0(FP), R0 // fd
MOVD $2, R1 // F_SETFD
MOVD $1, R2 // FD_CLOEXEC
MOVD $SYS_fcntl, R8
SVC
RET
......@@ -357,6 +357,10 @@ func gentraceback(pc0, sp0, lr0 uintptr, gp *g, skip int, pcbuf *uintptr, max in
if usesLR && waspanic {
x := *(*uintptr)(unsafe.Pointer(frame.sp))
frame.sp += ptrSize
if GOARCH == "arm64" {
// arm64 needs 16-byte aligned SP, always
frame.sp += ptrSize
}
f = findfunc(frame.pc)
frame.fn = f
if f == nil {
......
......@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build 386 amd64 amd64p32
// +build 386 amd64 amd64p32 arm64
package runtime
......
......@@ -8,5 +8,6 @@ const goarch_386 = 1
const goarch_amd64 = 0
const goarch_amd64p32 = 0
const goarch_arm = 0
const goarch_arm64 = 0
const goarch_ppc64 = 0
const goarch_ppc64le = 0
......@@ -8,5 +8,6 @@ const goarch_386 = 0
const goarch_amd64 = 1
const goarch_amd64p32 = 0
const goarch_arm = 0
const goarch_arm64 = 0
const goarch_ppc64 = 0
const goarch_ppc64le = 0
......@@ -8,5 +8,6 @@ const goarch_386 = 0
const goarch_amd64 = 0
const goarch_amd64p32 = 1
const goarch_arm = 0
const goarch_arm64 = 0
const goarch_ppc64 = 0
const goarch_ppc64le = 0
......@@ -8,5 +8,6 @@ const goarch_386 = 0
const goarch_amd64 = 0
const goarch_amd64p32 = 0
const goarch_arm = 1
const goarch_arm64 = 0
const goarch_ppc64 = 0
const goarch_ppc64le = 0
// generated by gengoos.go using 'go generate'
package runtime
const theGoarch = `arm64`
const goarch_386 = 0
const goarch_amd64 = 0
const goarch_amd64p32 = 0
const goarch_arm = 0
const goarch_arm64 = 1
const goarch_ppc64 = 0
const goarch_ppc64le = 0
......@@ -8,5 +8,6 @@ const goarch_386 = 0
const goarch_amd64 = 0
const goarch_amd64p32 = 0
const goarch_arm = 0
const goarch_arm64 = 0
const goarch_ppc64 = 1
const goarch_ppc64le = 0
......@@ -8,5 +8,6 @@ const goarch_386 = 0
const goarch_amd64 = 0
const goarch_amd64p32 = 0
const goarch_arm = 0
const goarch_arm64 = 0
const goarch_ppc64 = 0
const goarch_ppc64le = 1
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment