summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMartin Möhrmann <moehrmann@google.com>2020-10-13 22:30:23 +0200
committerMartin Möhrmann <moehrmann@google.com>2020-10-20 11:09:52 +0000
commitde932da453f68b8fc04e9c2ab25136748173c806 (patch)
treed657dab40079de391135dffc4fab9fc159a1d005
parent55b2d479d774d9887a6ec32b34e2c413f7c84f78 (diff)
downloadgo-git-de932da453f68b8fc04e9c2ab25136748173c806.tar.gz
internal/cpu: consolidate arm64 feature detection
Move code to detect and mask arm64 CPU features from runtime to internal/cpu. Change-Id: Ib784e2ff056e8def125d68827b852f07a3eff0db Reviewed-on: https://go-review.googlesource.com/c/go/+/261878 Trust: Martin Möhrmann <moehrmann@google.com> Trust: Tobias Klauser <tobias.klauser@gmail.com> Run-TryBot: Tobias Klauser <tobias.klauser@gmail.com> TryBot-Result: Go Bot <gobot@golang.org> Reviewed-by: Tobias Klauser <tobias.klauser@gmail.com> Reviewed-by: Benny Siegert <bsiegert@gmail.com>
-rw-r--r--src/internal/cpu/cpu_android.go7
-rw-r--r--src/internal/cpu/cpu_arm64.go73
-rw-r--r--src/internal/cpu/cpu_arm64.s12
-rw-r--r--src/internal/cpu/cpu_freebsd.go7
-rw-r--r--src/internal/cpu/cpu_linux.go9
-rw-r--r--src/internal/cpu/cpu_other.go11
-rw-r--r--src/runtime/auxv_none.go1
-rw-r--r--src/runtime/os_freebsd_arm64.go143
-rw-r--r--src/runtime/os_freebsd_noauxv.go2
-rw-r--r--src/runtime/os_linux_arm64.go14
-rw-r--r--src/runtime/os_netbsd.go1
-rw-r--r--src/runtime/os_netbsd_386.go3
-rw-r--r--src/runtime/os_netbsd_amd64.go3
-rw-r--r--src/runtime/os_netbsd_arm.go3
-rw-r--r--src/runtime/os_netbsd_arm64.go12
-rw-r--r--src/runtime/os_openbsd_arm64.go11
-rw-r--r--src/runtime/sys_freebsd_arm64.s21
17 files changed, 110 insertions, 223 deletions
diff --git a/src/internal/cpu/cpu_android.go b/src/internal/cpu/cpu_android.go
new file mode 100644
index 0000000000..d995e8d5a7
--- /dev/null
+++ b/src/internal/cpu/cpu_android.go
@@ -0,0 +1,7 @@
+// Copyright 2020 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 cpu
+
+const GOOS = "android"
diff --git a/src/internal/cpu/cpu_arm64.go b/src/internal/cpu/cpu_arm64.go
index d9e0c98ca6..533bea2470 100644
--- a/src/internal/cpu/cpu_arm64.go
+++ b/src/internal/cpu/cpu_arm64.go
@@ -6,13 +6,11 @@ package cpu
const CacheLinePadSize = 64
-// arm64 doesn't have a 'cpuid' equivalent, so we rely on HWCAP/HWCAP2.
-// These are initialized by archauxv and should not be changed after they are
-// initialized.
+// HWCap may be initialized by archauxv and
+// should not be changed after it was initialized.
var HWCap uint
-var HWCap2 uint
-// HWCAP/HWCAP2 bits. These are exposed by Linux.
+// HWCAP bits. These are exposed by Linux.
const (
hwcap_AES = 1 << 3
hwcap_PMULL = 1 << 4
@@ -32,15 +30,66 @@ func doinit() {
{Name: "atomics", Feature: &ARM64.HasATOMICS},
}
- // HWCAP feature bits
- ARM64.HasAES = isSet(HWCap, hwcap_AES)
- ARM64.HasPMULL = isSet(HWCap, hwcap_PMULL)
- ARM64.HasSHA1 = isSet(HWCap, hwcap_SHA1)
- ARM64.HasSHA2 = isSet(HWCap, hwcap_SHA2)
- ARM64.HasCRC32 = isSet(HWCap, hwcap_CRC32)
- ARM64.HasATOMICS = isSet(HWCap, hwcap_ATOMICS)
+ switch GOOS {
+ case "linux", "android":
+ // HWCap was populated by the runtime from the auxillary vector.
+ // Use HWCap information since reading aarch64 system registers
+ // is not supported in user space on older linux kernels.
+ ARM64.HasAES = isSet(HWCap, hwcap_AES)
+ ARM64.HasPMULL = isSet(HWCap, hwcap_PMULL)
+ ARM64.HasSHA1 = isSet(HWCap, hwcap_SHA1)
+ ARM64.HasSHA2 = isSet(HWCap, hwcap_SHA2)
+ ARM64.HasCRC32 = isSet(HWCap, hwcap_CRC32)
+
+ // The Samsung S9+ kernel reports support for atomics, but not all cores
+ // actually support them, resulting in SIGILL. See issue #28431.
+ // TODO(elias.naur): Only disable the optimization on bad chipsets on android.
+ ARM64.HasATOMICS = isSet(HWCap, hwcap_ATOMICS) && GOOS != "android"
+
+ case "freebsd":
+ // Retrieve info from system register ID_AA64ISAR0_EL1.
+ isar0 := getisar0()
+
+ // ID_AA64ISAR0_EL1
+ switch extractBits(isar0, 4, 7) {
+ case 1:
+ ARM64.HasAES = true
+ case 2:
+ ARM64.HasAES = true
+ ARM64.HasPMULL = true
+ }
+
+ switch extractBits(isar0, 8, 11) {
+ case 1:
+ ARM64.HasSHA1 = true
+ }
+
+ switch extractBits(isar0, 12, 15) {
+ case 1, 2:
+ ARM64.HasSHA2 = true
+ }
+
+ switch extractBits(isar0, 16, 19) {
+ case 1:
+ ARM64.HasCRC32 = true
+ }
+
+ switch extractBits(isar0, 20, 23) {
+ case 2:
+ ARM64.HasATOMICS = true
+ }
+ default:
+ // Other operating systems do not support reading HWCap from auxillary vector
+ // or reading privileged aarch64 system registers in user space.
+ }
+}
+
+func extractBits(data uint64, start, end uint) uint {
+ return (uint)(data>>start) & ((1 << (end - start + 1)) - 1)
}
func isSet(hwc uint, value uint) bool {
return hwc&value != 0
}
+
+func getisar0() uint64
diff --git a/src/internal/cpu/cpu_arm64.s b/src/internal/cpu/cpu_arm64.s
new file mode 100644
index 0000000000..d85914973f
--- /dev/null
+++ b/src/internal/cpu/cpu_arm64.s
@@ -0,0 +1,12 @@
+// Copyright 2020 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"
+
+// func getisar0() uint64
+TEXT ·getisar0(SB),NOSPLIT,$0
+ // get Instruction Set Attributes 0 into R0
+ MRS ID_AA64ISAR0_EL1, R0
+ MOVD R0, ret+0(FP)
+ RET
diff --git a/src/internal/cpu/cpu_freebsd.go b/src/internal/cpu/cpu_freebsd.go
new file mode 100644
index 0000000000..dc37173dac
--- /dev/null
+++ b/src/internal/cpu/cpu_freebsd.go
@@ -0,0 +1,7 @@
+// Copyright 2020 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 cpu
+
+const GOOS = "freebsd"
diff --git a/src/internal/cpu/cpu_linux.go b/src/internal/cpu/cpu_linux.go
new file mode 100644
index 0000000000..ec0b84c510
--- /dev/null
+++ b/src/internal/cpu/cpu_linux.go
@@ -0,0 +1,9 @@
+// Copyright 2020 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 !android
+
+package cpu
+
+const GOOS = "linux"
diff --git a/src/internal/cpu/cpu_other.go b/src/internal/cpu/cpu_other.go
new file mode 100644
index 0000000000..8a15fbe79d
--- /dev/null
+++ b/src/internal/cpu/cpu_other.go
@@ -0,0 +1,11 @@
+// Copyright 2020 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 !freebsd
+// +build !android
+
+package cpu
+
+const GOOS = "other"
diff --git a/src/runtime/auxv_none.go b/src/runtime/auxv_none.go
index 3a560a1793..3ca617b21e 100644
--- a/src/runtime/auxv_none.go
+++ b/src/runtime/auxv_none.go
@@ -7,7 +7,6 @@
// +build !dragonfly
// +build !freebsd
// +build !netbsd
-// +build !openbsd !arm64
// +build !solaris
package runtime
diff --git a/src/runtime/os_freebsd_arm64.go b/src/runtime/os_freebsd_arm64.go
index 51ebf9d478..b5b25f0dc5 100644
--- a/src/runtime/os_freebsd_arm64.go
+++ b/src/runtime/os_freebsd_arm64.go
@@ -4,149 +4,6 @@
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().
diff --git a/src/runtime/os_freebsd_noauxv.go b/src/runtime/os_freebsd_noauxv.go
index c6a49927c8..01efb9b7c9 100644
--- a/src/runtime/os_freebsd_noauxv.go
+++ b/src/runtime/os_freebsd_noauxv.go
@@ -3,7 +3,7 @@
// license that can be found in the LICENSE file.
// +build freebsd
-// +build !arm,!arm64
+// +build !arm
package runtime
diff --git a/src/runtime/os_linux_arm64.go b/src/runtime/os_linux_arm64.go
index 19968dc164..c5fd742048 100644
--- a/src/runtime/os_linux_arm64.go
+++ b/src/runtime/os_linux_arm64.go
@@ -11,19 +11,7 @@ import "internal/cpu"
func archauxv(tag, val uintptr) {
switch tag {
case _AT_HWCAP:
- // arm64 doesn't have a 'cpuid' instruction equivalent and relies on
- // HWCAP/HWCAP2 bits for hardware capabilities.
- hwcap := uint(val)
- if GOOS == "android" {
- // The Samsung S9+ kernel reports support for atomics, but not all cores
- // actually support them, resulting in SIGILL. See issue #28431.
- // TODO(elias.naur): Only disable the optimization on bad chipsets.
- const hwcap_ATOMICS = 1 << 8
- hwcap &= ^uint(hwcap_ATOMICS)
- }
- cpu.HWCap = hwcap
- case _AT_HWCAP2:
- cpu.HWCap2 = uint(val)
+ cpu.HWCap = uint(val)
}
}
diff --git a/src/runtime/os_netbsd.go b/src/runtime/os_netbsd.go
index c4c3d8e2fe..f7f90cedc1 100644
--- a/src/runtime/os_netbsd.go
+++ b/src/runtime/os_netbsd.go
@@ -359,7 +359,6 @@ func sysargs(argc int32, argv **byte) {
// now argv+n is auxv
auxv := (*[1 << 28]uintptr)(add(unsafe.Pointer(argv), uintptr(n)*sys.PtrSize))
sysauxv(auxv[:])
- archauxv(auxv[:])
}
const (
diff --git a/src/runtime/os_netbsd_386.go b/src/runtime/os_netbsd_386.go
index c203af9cef..037f7e36dc 100644
--- a/src/runtime/os_netbsd_386.go
+++ b/src/runtime/os_netbsd_386.go
@@ -14,6 +14,3 @@ func lwp_mcontext_init(mc *mcontextt, stk unsafe.Pointer, mp *m, gp *g, fn uintp
mc.__gregs[_REG_EDX] = uint32(uintptr(unsafe.Pointer(gp)))
mc.__gregs[_REG_ESI] = uint32(fn)
}
-
-func archauxv(auxv []uintptr) {
-}
diff --git a/src/runtime/os_netbsd_amd64.go b/src/runtime/os_netbsd_amd64.go
index ea9d125492..5118b0c4ff 100644
--- a/src/runtime/os_netbsd_amd64.go
+++ b/src/runtime/os_netbsd_amd64.go
@@ -14,6 +14,3 @@ func lwp_mcontext_init(mc *mcontextt, stk unsafe.Pointer, mp *m, gp *g, fn uintp
mc.__gregs[_REG_R9] = uint64(uintptr(unsafe.Pointer(gp)))
mc.__gregs[_REG_R12] = uint64(fn)
}
-
-func archauxv(auxv []uintptr) {
-}
diff --git a/src/runtime/os_netbsd_arm.go b/src/runtime/os_netbsd_arm.go
index 646da9dc0b..b5ec23e45b 100644
--- a/src/runtime/os_netbsd_arm.go
+++ b/src/runtime/os_netbsd_arm.go
@@ -32,6 +32,3 @@ func cputicks() int64 {
// runtime·nanotime() is a poor approximation of CPU ticks that is enough for the profiler.
return nanotime()
}
-
-func archauxv(auxv []uintptr) {
-}
diff --git a/src/runtime/os_netbsd_arm64.go b/src/runtime/os_netbsd_arm64.go
index ae2638c778..8d21b0a430 100644
--- a/src/runtime/os_netbsd_arm64.go
+++ b/src/runtime/os_netbsd_arm64.go
@@ -4,10 +4,7 @@
package runtime
-import (
- "internal/cpu"
- "unsafe"
-)
+import "unsafe"
func lwp_mcontext_init(mc *mcontextt, stk unsafe.Pointer, mp *m, gp *g, fn uintptr) {
// Machine dependent mcontext initialisation for LWP.
@@ -24,10 +21,3 @@ func cputicks() int64 {
// runtime·nanotime() is a poor approximation of CPU ticks that is enough for the profiler.
return nanotime()
}
-
-func archauxv(auxv []uintptr) {
- // NetBSD does not supply AT_HWCAP, however we still need to initialise cpu.HWCaps.
- // For now specify the bare minimum until we add some form of capabilities
- // detection. See issue https://golang.org/issue/30824#issuecomment-494901591
- cpu.HWCap = 1<<1 | 1<<0 // ASIMD, FP
-}
diff --git a/src/runtime/os_openbsd_arm64.go b/src/runtime/os_openbsd_arm64.go
index d559a2a3e5..d71de7d196 100644
--- a/src/runtime/os_openbsd_arm64.go
+++ b/src/runtime/os_openbsd_arm64.go
@@ -4,20 +4,9 @@
package runtime
-import (
- "internal/cpu"
-)
-
//go:nosplit
func cputicks() int64 {
// Currently cputicks() is used in blocking profiler and to seed runtime·fastrand().
// runtime·nanotime() is a poor approximation of CPU ticks that is enough for the profiler.
return nanotime()
}
-
-func sysargs(argc int32, argv **byte) {
- // OpenBSD does not have auxv, however we still need to initialise cpu.HWCaps.
- // For now specify the bare minimum until we add some form of capabilities
- // detection. See issue #31746.
- cpu.HWCap = 1<<1 | 1<<0 // ASIMD, FP
-}
diff --git a/src/runtime/sys_freebsd_arm64.s b/src/runtime/sys_freebsd_arm64.s
index 2330f2ffe2..8a4f9b7fa1 100644
--- a/src/runtime/sys_freebsd_arm64.s
+++ b/src/runtime/sys_freebsd_arm64.s
@@ -515,24 +515,3 @@ TEXT runtime·getCntxct(SB),NOSPLIT,$0
MOVW R0, ret+8(FP)
RET
-
-// func getisar0() uint64
-TEXT runtime·getisar0(SB),NOSPLIT,$0
- // get Instruction Set Attributes 0 into R0
- MRS ID_AA64ISAR0_EL1, R0
- MOVD R0, ret+0(FP)
- RET
-
-// func getisar1() uint64
-TEXT runtime·getisar1(SB),NOSPLIT,$0
- // get Instruction Set Attributes 1 into R0
- MRS ID_AA64ISAR1_EL1, R0
- MOVD R0, ret+0(FP)
- RET
-
-// func getpfr0() uint64
-TEXT runtime·getpfr0(SB),NOSPLIT,$0
- // get Processor Feature Register 0 into R0
- MRS ID_AA64PFR0_EL1, R0
- MOVD R0, ret+0(FP)
- RET