Commit 6b6e67f9 authored by Tobias Klauser's avatar Tobias Klauser Committed by Tobias Klauser

runtime: add support for freebsd/arm64

Based on work by Mikaël Urankar (@MikaelUrankar),
Shigeru YAMAMOTO (@bsd-hacker) and @myfreeweb.

Updates #24715

Change-Id: If3189a693ca0aa627029e22b0f91534bcf322bc0
Reviewed-on: https://go-review.googlesource.com/c/go/+/198544
Run-TryBot: Tobias Klauser <tobias.klauser@gmail.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: default avatarBrad Fitzpatrick <bradfitz@golang.org>
parent fc8eb264
// created by cgo -cdefs and then converted to Go
// cgo -cdefs defs_freebsd.go
package runtime
import "unsafe"
const (
_NBBY = 0x8
_CTL_MAXNAME = 0x18
_CPU_LEVEL_WHICH = 0x3
_CPU_WHICH_PID = 0x2
)
const (
_EINTR = 0x4
_EFAULT = 0xe
_EAGAIN = 0x23
_ENOSYS = 0x4e
_O_NONBLOCK = 0x4
_O_CLOEXEC = 0x100000
_PROT_NONE = 0x0
_PROT_READ = 0x1
_PROT_WRITE = 0x2
_PROT_EXEC = 0x4
_MAP_ANON = 0x1000
_MAP_SHARED = 0x1
_MAP_PRIVATE = 0x2
_MAP_FIXED = 0x10
_MADV_FREE = 0x5
_SA_SIGINFO = 0x40
_SA_RESTART = 0x2
_SA_ONSTACK = 0x1
_CLOCK_MONOTONIC = 0x4
_CLOCK_REALTIME = 0x0
_UMTX_OP_WAIT_UINT = 0xb
_UMTX_OP_WAIT_UINT_PRIVATE = 0xf
_UMTX_OP_WAKE = 0x3
_UMTX_OP_WAKE_PRIVATE = 0x10
_SIGHUP = 0x1
_SIGINT = 0x2
_SIGQUIT = 0x3
_SIGILL = 0x4
_SIGTRAP = 0x5
_SIGABRT = 0x6
_SIGEMT = 0x7
_SIGFPE = 0x8
_SIGKILL = 0x9
_SIGBUS = 0xa
_SIGSEGV = 0xb
_SIGSYS = 0xc
_SIGPIPE = 0xd
_SIGALRM = 0xe
_SIGTERM = 0xf
_SIGURG = 0x10
_SIGSTOP = 0x11
_SIGTSTP = 0x12
_SIGCONT = 0x13
_SIGCHLD = 0x14
_SIGTTIN = 0x15
_SIGTTOU = 0x16
_SIGIO = 0x17
_SIGXCPU = 0x18
_SIGXFSZ = 0x19
_SIGVTALRM = 0x1a
_SIGPROF = 0x1b
_SIGWINCH = 0x1c
_SIGINFO = 0x1d
_SIGUSR1 = 0x1e
_SIGUSR2 = 0x1f
_FPE_INTDIV = 0x2
_FPE_INTOVF = 0x1
_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
_EV_ADD = 0x1
_EV_DELETE = 0x2
_EV_CLEAR = 0x20
_EV_RECEIPT = 0x40
_EV_ERROR = 0x4000
_EV_EOF = 0x8000
_EVFILT_READ = -0x1
_EVFILT_WRITE = -0x2
)
type rtprio struct {
_type uint16
prio uint16
}
type thrparam struct {
start_func uintptr
arg unsafe.Pointer
stack_base uintptr
stack_size uintptr
tls_base unsafe.Pointer
tls_size uintptr
child_tid unsafe.Pointer // *int64
parent_tid *int64
flags int32
pad_cgo_0 [4]byte
rtp *rtprio
spare [3]uintptr
}
type sigset struct {
__bits [4]uint32
}
type stackt struct {
ss_sp uintptr
ss_size uintptr
ss_flags int32
pad_cgo_0 [4]byte
}
type siginfo struct {
si_signo int32
si_errno int32
si_code int32
si_pid int32
si_uid uint32
si_status int32
si_addr uint64
si_value [8]byte
_reason [40]byte
}
type gpregs struct {
gp_x [30]uint64
gp_lr uint64
gp_sp uint64
gp_elr uint64
gp_spsr uint32
gp_pad int32
}
type fpregs struct {
fp_q [64]uint64 // actually [32]uint128
fp_sr uint32
fp_cr uint32
fp_flags int32
fp_pad int32
}
type mcontext struct {
mc_gpregs gpregs
mc_fpregs fpregs
mc_flags int32
mc_pad int32
mc_spare [8]uint64
}
type ucontext struct {
uc_sigmask sigset
uc_mcontext mcontext
uc_link *ucontext
uc_stack stackt
uc_flags int32
__spare__ [4]int32
pad_cgo_0 [12]byte
}
type timespec struct {
tv_sec int64
tv_nsec int64
}
//go:nosplit
func (ts *timespec) setNsec(ns int64) {
ts.tv_sec = ns / 1e9
ts.tv_nsec = ns % 1e9
}
type timeval struct {
tv_sec int64
tv_usec int64
}
func (tv *timeval) set_usec(x int32) {
tv.tv_usec = int64(x)
}
type itimerval struct {
it_interval timeval
it_value timeval
}
type umtx_time struct {
_timeout timespec
_flags uint32
_clockid uint32
}
type keventt struct {
ident uint64
filter int16
flags uint16
fflags uint32
data int64
udata *byte
}
type bintime struct {
sec int64
frac uint64
}
type vdsoTimehands struct {
algo uint32
gen uint32
scale uint64
offset_count uint32
counter_mask uint32
offset bintime
boottime bintime
physical uint32
res [7]uint32
}
type vdsoTimekeep struct {
ver uint32
enabled uint32
current uint32
pad_cgo_0 [4]byte
}
const (
_VDSO_TK_VER_CURR = 0x1
vdsoTimehandsSize = 0x58
vdsoTimekeepSize = 0x10
)
// Copyright 2019 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 "internal/cpu"
const (
hwcap_FP = 1 << 0
hwcap_ASIMD = 1 << 1
hwcap_EVTSTRM = 1 << 2
hwcap_AES = 1 << 3
hwcap_PMULL = 1 << 4
hwcap_SHA1 = 1 << 5
hwcap_SHA2 = 1 << 6
hwcap_CRC32 = 1 << 7
hwcap_ATOMICS = 1 << 8
hwcap_FPHP = 1 << 9
hwcap_ASIMDHP = 1 << 10
hwcap_CPUID = 1 << 11
hwcap_ASIMDRDM = 1 << 12
hwcap_JSCVT = 1 << 13
hwcap_FCMA = 1 << 14
hwcap_LRCPC = 1 << 15
hwcap_DCPOP = 1 << 16
hwcap_SHA3 = 1 << 17
hwcap_SM3 = 1 << 18
hwcap_SM4 = 1 << 19
hwcap_ASIMDDP = 1 << 20
hwcap_SHA512 = 1 << 21
hwcap_SVE = 1 << 22
hwcap_ASIMDFHM = 1 << 23
)
func getisar0() uint64
func getisar1() uint64
func getpfr0() uint64
// no hwcap support on FreeBSD aarch64, we need to retrieve the info from
// ID_AA64ISAR0_EL1, ID_AA64ISAR1_EL1 and ID_AA64PFR0_EL1
func archauxv(tag, val uintptr) {
var isar0, isar1, pfr0 uint64
isar0 = getisar0()
isar1 = getisar1()
pfr0 = getpfr0()
// ID_AA64ISAR0_EL1
switch extractBits(isar0, 4, 7) {
case 1:
cpu.HWCap |= hwcap_AES
case 2:
cpu.HWCap |= hwcap_PMULL | hwcap_AES
}
switch extractBits(isar0, 8, 11) {
case 1:
cpu.HWCap |= hwcap_SHA1
}
switch extractBits(isar0, 12, 15) {
case 1:
cpu.HWCap |= hwcap_SHA2
case 2:
cpu.HWCap |= hwcap_SHA2 | hwcap_SHA512
}
switch extractBits(isar0, 16, 19) {
case 1:
cpu.HWCap |= hwcap_CRC32
}
switch extractBits(isar0, 20, 23) {
case 2:
cpu.HWCap |= hwcap_ATOMICS
}
switch extractBits(isar0, 28, 31) {
case 1:
cpu.HWCap |= hwcap_ASIMDRDM
}
switch extractBits(isar0, 32, 35) {
case 1:
cpu.HWCap |= hwcap_SHA3
}
switch extractBits(isar0, 36, 39) {
case 1:
cpu.HWCap |= hwcap_SM3
}
switch extractBits(isar0, 40, 43) {
case 1:
cpu.HWCap |= hwcap_SM4
}
switch extractBits(isar0, 44, 47) {
case 1:
cpu.HWCap |= hwcap_ASIMDDP
}
// ID_AA64ISAR1_EL1
switch extractBits(isar1, 0, 3) {
case 1:
cpu.HWCap |= hwcap_DCPOP
}
switch extractBits(isar1, 12, 15) {
case 1:
cpu.HWCap |= hwcap_JSCVT
}
switch extractBits(isar1, 16, 19) {
case 1:
cpu.HWCap |= hwcap_FCMA
}
switch extractBits(isar1, 20, 23) {
case 1:
cpu.HWCap |= hwcap_LRCPC
}
// ID_AA64PFR0_EL1
switch extractBits(pfr0, 16, 19) {
case 0:
cpu.HWCap |= hwcap_FP
case 1:
cpu.HWCap |= hwcap_FP | hwcap_FPHP
}
switch extractBits(pfr0, 20, 23) {
case 0:
cpu.HWCap |= hwcap_ASIMD
case 1:
cpu.HWCap |= hwcap_ASIMD | hwcap_ASIMDHP
}
switch extractBits(pfr0, 32, 35) {
case 1:
cpu.HWCap |= hwcap_SVE
}
}
func extractBits(data uint64, start, end uint) uint {
return (uint)(data>>start) & ((1 << (end - start + 1)) - 1)
}
//go:nosplit
func cputicks() int64 {
// Currently cputicks() is used in blocking profiler and to seed fastrand().
// nanotime() is a poor approximation of CPU ticks that is enough for the profiler.
// TODO: need more entropy to better seed fastrand.
return nanotime()
}
......@@ -3,7 +3,7 @@
// license that can be found in the LICENSE file.
// +build freebsd
// +build !arm
// +build !arm,!arm64
package runtime
......
// Copyright 2019 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"
// On FreeBSD argc/argv are passed in R0, not RSP
TEXT _rt0_arm64_freebsd(SB),NOSPLIT|NOFRAME,$0
ADD $8, R0, R1 // argv
MOVD 0(R0), R0 // argc
BL main(SB)
// When building with -buildmode=c-shared, this symbol is called when the shared
// library is loaded.
TEXT _rt0_arm64_freebsd_lib(SB),NOSPLIT,$184
// Preserve callee-save registers.
MOVD R19, 24(RSP)
MOVD R20, 32(RSP)
MOVD R21, 40(RSP)
MOVD R22, 48(RSP)
MOVD R23, 56(RSP)
MOVD R24, 64(RSP)
MOVD R25, 72(RSP)
MOVD R26, 80(RSP)
MOVD R27, 88(RSP)
FMOVD F8, 96(RSP)
FMOVD F9, 104(RSP)
FMOVD F10, 112(RSP)
FMOVD F11, 120(RSP)
FMOVD F12, 128(RSP)
FMOVD F13, 136(RSP)
FMOVD F14, 144(RSP)
FMOVD F15, 152(RSP)
MOVD g, 160(RSP)
// Initialize g as null in case of using g later e.g. sigaction in cgo_sigaction.go
MOVD ZR, g
MOVD R0, _rt0_arm64_freebsd_lib_argc<>(SB)
MOVD R1, _rt0_arm64_freebsd_lib_argv<>(SB)
// Synchronous initialization.
MOVD $runtime·libpreinit(SB), R4
BL (R4)
// Create a new thread to do the runtime initialization and return.
MOVD _cgo_sys_thread_create(SB), R4
CMP $0, R4
BEQ nocgo
MOVD $_rt0_arm64_freebsd_lib_go(SB), R0
MOVD $0, R1
SUB $16, RSP // reserve 16 bytes for sp-8 where fp may be saved.
BL (R4)
ADD $16, RSP
B restore
nocgo:
MOVD $0x800000, R0 // stacksize = 8192KB
MOVD $_rt0_arm64_freebsd_lib_go(SB), R1
MOVD R0, 8(RSP)
MOVD R1, 16(RSP)
MOVD $runtime·newosproc0(SB),R4
BL (R4)
restore:
// Restore callee-save registers.
MOVD 24(RSP), R19
MOVD 32(RSP), R20
MOVD 40(RSP), R21
MOVD 48(RSP), R22
MOVD 56(RSP), R23
MOVD 64(RSP), R24
MOVD 72(RSP), R25
MOVD 80(RSP), R26
MOVD 88(RSP), R27
FMOVD 96(RSP), F8
FMOVD 104(RSP), F9
FMOVD 112(RSP), F10
FMOVD 120(RSP), F11
FMOVD 128(RSP), F12
FMOVD 136(RSP), F13
FMOVD 144(RSP), F14
FMOVD 152(RSP), F15
MOVD 160(RSP), g
RET
TEXT _rt0_arm64_freebsd_lib_go(SB),NOSPLIT,$0
MOVD _rt0_arm64_freebsd_lib_argc<>(SB), R0
MOVD _rt0_arm64_freebsd_lib_argv<>(SB), R1
MOVD $runtime·rt0_go(SB),R4
B (R4)
DATA _rt0_arm64_freebsd_lib_argc<>(SB)/8, $0
GLOBL _rt0_arm64_freebsd_lib_argc<>(SB),NOPTR, $8
DATA _rt0_arm64_freebsd_lib_argv<>(SB)/8, $0
GLOBL _rt0_arm64_freebsd_lib_argv<>(SB),NOPTR, $8
TEXT main(SB),NOSPLIT|NOFRAME,$0
MOVD $runtime·rt0_go(SB), R2
BL (R2)
exit:
MOVD $0, R0
MOVD $1, R8 // SYS_exit
SVC
B exit
......@@ -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 darwin linux netbsd openbsd
// +build darwin freebsd linux netbsd openbsd
package runtime
......
// Copyright 2019 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
}
//go:nosplit
//go:nowritebarrierrec
func (c *sigctxt) regs() *mcontext { return &(*ucontext)(c.ctxt).uc_mcontext }
func (c *sigctxt) r0() uint64 { return c.regs().mc_gpregs.gp_x[0] }
func (c *sigctxt) r1() uint64 { return c.regs().mc_gpregs.gp_x[1] }
func (c *sigctxt) r2() uint64 { return c.regs().mc_gpregs.gp_x[2] }
func (c *sigctxt) r3() uint64 { return c.regs().mc_gpregs.gp_x[3] }
func (c *sigctxt) r4() uint64 { return c.regs().mc_gpregs.gp_x[4] }
func (c *sigctxt) r5() uint64 { return c.regs().mc_gpregs.gp_x[5] }
func (c *sigctxt) r6() uint64 { return c.regs().mc_gpregs.gp_x[6] }
func (c *sigctxt) r7() uint64 { return c.regs().mc_gpregs.gp_x[7] }
func (c *sigctxt) r8() uint64 { return c.regs().mc_gpregs.gp_x[8] }
func (c *sigctxt) r9() uint64 { return c.regs().mc_gpregs.gp_x[9] }
func (c *sigctxt) r10() uint64 { return c.regs().mc_gpregs.gp_x[10] }
func (c *sigctxt) r11() uint64 { return c.regs().mc_gpregs.gp_x[11] }
func (c *sigctxt) r12() uint64 { return c.regs().mc_gpregs.gp_x[12] }
func (c *sigctxt) r13() uint64 { return c.regs().mc_gpregs.gp_x[13] }
func (c *sigctxt) r14() uint64 { return c.regs().mc_gpregs.gp_x[14] }
func (c *sigctxt) r15() uint64 { return c.regs().mc_gpregs.gp_x[15] }
func (c *sigctxt) r16() uint64 { return c.regs().mc_gpregs.gp_x[16] }
func (c *sigctxt) r17() uint64 { return c.regs().mc_gpregs.gp_x[17] }
func (c *sigctxt) r18() uint64 { return c.regs().mc_gpregs.gp_x[18] }
func (c *sigctxt) r19() uint64 { return c.regs().mc_gpregs.gp_x[19] }
func (c *sigctxt) r20() uint64 { return c.regs().mc_gpregs.gp_x[20] }
func (c *sigctxt) r21() uint64 { return c.regs().mc_gpregs.gp_x[21] }
func (c *sigctxt) r22() uint64 { return c.regs().mc_gpregs.gp_x[22] }
func (c *sigctxt) r23() uint64 { return c.regs().mc_gpregs.gp_x[23] }
func (c *sigctxt) r24() uint64 { return c.regs().mc_gpregs.gp_x[24] }
func (c *sigctxt) r25() uint64 { return c.regs().mc_gpregs.gp_x[25] }
func (c *sigctxt) r26() uint64 { return c.regs().mc_gpregs.gp_x[26] }
func (c *sigctxt) r27() uint64 { return c.regs().mc_gpregs.gp_x[27] }
func (c *sigctxt) r28() uint64 { return c.regs().mc_gpregs.gp_x[28] }
func (c *sigctxt) r29() uint64 { return c.regs().mc_gpregs.gp_x[29] }
func (c *sigctxt) lr() uint64 { return c.regs().mc_gpregs.gp_lr }
func (c *sigctxt) sp() uint64 { return c.regs().mc_gpregs.gp_sp }
//go:nosplit
//go:nowritebarrierrec
func (c *sigctxt) pc() uint64 { return c.regs().mc_gpregs.gp_elr }
func (c *sigctxt) fault() uint64 { return c.info.si_addr }
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().mc_gpregs.gp_elr = x }
func (c *sigctxt) set_sp(x uint64) { c.regs().mc_gpregs.gp_sp = x }
func (c *sigctxt) set_lr(x uint64) { c.regs().mc_gpregs.gp_lr = x }
func (c *sigctxt) set_r28(x uint64) { c.regs().mc_gpregs.gp_x[28] = x }
func (c *sigctxt) set_sigcode(x uint64) { c.info.si_code = int32(x) }
func (c *sigctxt) set_sigaddr(x uint64) { c.info.si_addr = x }
......@@ -7,3 +7,4 @@ package runtime
// Called from assembly only; declared for go vet.
func load_g()
func save_g()
func emptyfunc()
This diff is collapsed.
......@@ -20,6 +20,11 @@
#define MRS_TPIDR_R0 WORD $0xd53bd060 // MRS TPIDRRO_EL0, R0
#endif
#ifdef GOOS_freebsd
#define TPIDR TPIDR_EL0
#define MRS_TPIDR_R0 WORD $0xd53bd040 // MRS TPIDR_EL0, R0
#endif
#ifdef GOOS_netbsd
#define TPIDR TPIDRRO_EL0
#define MRS_TPIDR_R0 WORD $0xd53bd040 // MRS TPIDRRO_EL0, R0
......
// Copyright 2019 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 (
_VDSO_TH_ALGO_ARM_GENTIM = 1
)
func getCntxct(physical bool) uint32
//go:nosplit
func (th *vdsoTimehands) getTimecounter() (uint32, bool) {
switch th.algo {
case _VDSO_TH_ALGO_ARM_GENTIM:
return getCntxct(false), true
default:
return 0, false
}
}
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