aboutsummaryrefslogtreecommitdiff
path: root/src/internal
diff options
context:
space:
mode:
authorMartin Möhrmann <moehrmann@google.com>2020-11-21 17:44:04 +0100
committerMartin Möhrmann <moehrmann@google.com>2020-12-07 07:59:54 +0000
commitc15593197453b8bf90fc3a9080ba2afeaf7934ea (patch)
treed0c9e386625721d141867690e427dfd8c84d5c62 /src/internal
parente10c94af26b95f4af71c4a040b3d3f01499d01de (diff)
downloadgo-c15593197453b8bf90fc3a9080ba2afeaf7934ea.tar.gz
go-c15593197453b8bf90fc3a9080ba2afeaf7934ea.zip
internal/cpu: add darwin/arm64 CPU feature detection support
Fixes #42747 Change-Id: I6b1679348c77161f075f0678818bb003fc0e8c86 Reviewed-on: https://go-review.googlesource.com/c/go/+/271989 Trust: Martin Möhrmann <moehrmann@google.com> Run-TryBot: Martin Möhrmann <martisch@uos.de> TryBot-Result: Go Bot <gobot@golang.org> Reviewed-by: Cherry Zhang <cherryyz@google.com>
Diffstat (limited to 'src/internal')
-rw-r--r--src/internal/cpu/cpu_android.go7
-rw-r--r--src/internal/cpu/cpu_arm64.go97
-rw-r--r--src/internal/cpu/cpu_arm64_android.go (renamed from src/internal/cpu/cpu_linux.go)6
-rw-r--r--src/internal/cpu/cpu_arm64_darwin.go34
-rw-r--r--src/internal/cpu/cpu_arm64_freebsd.go45
-rw-r--r--src/internal/cpu/cpu_arm64_hwcap.go63
-rw-r--r--src/internal/cpu/cpu_arm64_linux.go (renamed from src/internal/cpu/cpu_other.go)8
-rw-r--r--src/internal/cpu/cpu_arm64_other.go17
-rw-r--r--src/internal/cpu/cpu_freebsd.go7
-rw-r--r--src/internal/cpu/cpu_test.go7
10 files changed, 172 insertions, 119 deletions
diff --git a/src/internal/cpu/cpu_android.go b/src/internal/cpu/cpu_android.go
deleted file mode 100644
index d995e8d5a7..0000000000
--- a/src/internal/cpu/cpu_android.go
+++ /dev/null
@@ -1,7 +0,0 @@
-// 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 a8f7b2b458..f64d9e4dd3 100644
--- a/src/internal/cpu/cpu_arm64.go
+++ b/src/internal/cpu/cpu_arm64.go
@@ -6,21 +6,6 @@ package cpu
const CacheLinePadSize = 64
-// HWCap may be initialized by archauxv and
-// should not be changed after it was initialized.
-var HWCap uint
-
-// HWCAP bits. These are exposed by Linux.
-const (
- 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_CPUID = 1 << 11
-)
-
func doinit() {
options = []option{
{Name: "aes", Feature: &ARM64.HasAES},
@@ -34,86 +19,8 @@ func doinit() {
{Name: "isZeus", Feature: &ARM64.IsZeus},
}
- switch GOOS {
- case "linux", "android":
- // HWCap was populated by the runtime from the auxiliary 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)
- ARM64.HasCPUID = isSet(HWCap, hwcap_CPUID)
-
- // 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"
-
- // Check to see if executing on a NeoverseN1 and in order to do that,
- // check the AUXV for the CPUID bit. The getMIDR function executes an
- // instruction which would normally be an illegal instruction, but it's
- // trapped by the kernel, the value sanitized and then returned. Without
- // the CPUID bit the kernel will not trap the instruction and the process
- // will be terminated with SIGILL.
- if ARM64.HasCPUID {
- midr := getMIDR()
- part_num := uint16((midr >> 4) & 0xfff)
- implementor := byte((midr >> 24) & 0xff)
-
- if implementor == 'A' && part_num == 0xd0c {
- ARM64.IsNeoverseN1 = true
- }
- if implementor == 'A' && part_num == 0xd40 {
- ARM64.IsZeus = true
- }
- }
-
- 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 auxiliary 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
+ // arm64 uses different ways to detect CPU features at runtime depending on the operating system.
+ osInit()
}
func getisar0() uint64
diff --git a/src/internal/cpu/cpu_linux.go b/src/internal/cpu/cpu_arm64_android.go
index ec0b84c510..3c9e57c52a 100644
--- a/src/internal/cpu/cpu_linux.go
+++ b/src/internal/cpu/cpu_arm64_android.go
@@ -2,8 +2,10 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build !android
+// +build arm64
package cpu
-const GOOS = "linux"
+func osInit() {
+ hwcapInit("android")
+}
diff --git a/src/internal/cpu/cpu_arm64_darwin.go b/src/internal/cpu/cpu_arm64_darwin.go
new file mode 100644
index 0000000000..e094b97f97
--- /dev/null
+++ b/src/internal/cpu/cpu_arm64_darwin.go
@@ -0,0 +1,34 @@
+// 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 arm64
+// +build darwin
+// +build !ios
+
+package cpu
+
+func osInit() {
+ ARM64.HasATOMICS = sysctlEnabled([]byte("hw.optional.armv8_1_atomics\x00"))
+ ARM64.HasCRC32 = sysctlEnabled([]byte("hw.optional.armv8_crc32\x00"))
+
+ // There are no hw.optional sysctl values for the below features on Mac OS 11.0
+ // to detect their supported state dynamically. Assume the CPU features that
+ // Apple Silicon M1 supports to be available as a minimal set of features
+ // to all Go programs running on darwin/arm64.
+ ARM64.HasAES = true
+ ARM64.HasPMULL = true
+ ARM64.HasSHA1 = true
+ ARM64.HasSHA2 = true
+}
+
+//go:noescape
+func getsysctlbyname(name []byte) (int32, int32)
+
+func sysctlEnabled(name []byte) bool {
+ ret, value := getsysctlbyname(name)
+ if ret < 0 {
+ return false
+ }
+ return value > 0
+}
diff --git a/src/internal/cpu/cpu_arm64_freebsd.go b/src/internal/cpu/cpu_arm64_freebsd.go
new file mode 100644
index 0000000000..9de2005c2e
--- /dev/null
+++ b/src/internal/cpu/cpu_arm64_freebsd.go
@@ -0,0 +1,45 @@
+// 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 arm64
+
+package cpu
+
+func osInit() {
+ // 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
+ }
+}
+
+func extractBits(data uint64, start, end uint) uint {
+ return (uint)(data>>start) & ((1 << (end - start + 1)) - 1)
+}
diff --git a/src/internal/cpu/cpu_arm64_hwcap.go b/src/internal/cpu/cpu_arm64_hwcap.go
new file mode 100644
index 0000000000..fdaf43e1a2
--- /dev/null
+++ b/src/internal/cpu/cpu_arm64_hwcap.go
@@ -0,0 +1,63 @@
+// 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 arm64
+// +build linux
+
+package cpu
+
+// HWCap may be initialized by archauxv and
+// should not be changed after it was initialized.
+var HWCap uint
+
+// HWCAP bits. These are exposed by Linux.
+const (
+ 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_CPUID = 1 << 11
+)
+
+func hwcapInit(os string) {
+ // HWCap was populated by the runtime from the auxiliary 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)
+ ARM64.HasCPUID = isSet(HWCap, hwcap_CPUID)
+
+ // 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) && os != "android"
+
+ // Check to see if executing on a NeoverseN1 and in order to do that,
+ // check the AUXV for the CPUID bit. The getMIDR function executes an
+ // instruction which would normally be an illegal instruction, but it's
+ // trapped by the kernel, the value sanitized and then returned. Without
+ // the CPUID bit the kernel will not trap the instruction and the process
+ // will be terminated with SIGILL.
+ if ARM64.HasCPUID {
+ midr := getMIDR()
+ part_num := uint16((midr >> 4) & 0xfff)
+ implementor := byte((midr >> 24) & 0xff)
+
+ if implementor == 'A' && part_num == 0xd0c {
+ ARM64.IsNeoverseN1 = true
+ }
+ if implementor == 'A' && part_num == 0xd40 {
+ ARM64.IsZeus = true
+ }
+ }
+}
+
+func isSet(hwc uint, value uint) bool {
+ return hwc&value != 0
+}
diff --git a/src/internal/cpu/cpu_other.go b/src/internal/cpu/cpu_arm64_linux.go
index 8a15fbe79d..2f7411ff1e 100644
--- a/src/internal/cpu/cpu_other.go
+++ b/src/internal/cpu/cpu_arm64_linux.go
@@ -2,10 +2,12 @@
// 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 arm64
+// +build linux
// +build !android
package cpu
-const GOOS = "other"
+func osInit() {
+ hwcapInit("linux")
+}
diff --git a/src/internal/cpu/cpu_arm64_other.go b/src/internal/cpu/cpu_arm64_other.go
new file mode 100644
index 0000000000..f191db28d2
--- /dev/null
+++ b/src/internal/cpu/cpu_arm64_other.go
@@ -0,0 +1,17 @@
+// 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 arm64
+// +build !linux
+// +build !freebsd
+// +build !android
+// +build !darwin ios
+
+package cpu
+
+func osInit() {
+ // Other operating systems do not support reading HWCap from auxiliary vector,
+ // reading privileged aarch64 system registers or sysctl in user space to detect
+ // CPU features at runtime.
+}
diff --git a/src/internal/cpu/cpu_freebsd.go b/src/internal/cpu/cpu_freebsd.go
deleted file mode 100644
index dc37173dac..0000000000
--- a/src/internal/cpu/cpu_freebsd.go
+++ /dev/null
@@ -1,7 +0,0 @@
-// 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_test.go b/src/internal/cpu/cpu_test.go
index 919bbd5ed7..2de7365732 100644
--- a/src/internal/cpu/cpu_test.go
+++ b/src/internal/cpu/cpu_test.go
@@ -18,7 +18,7 @@ func TestMinimalFeatures(t *testing.T) {
// TODO: maybe do MustSupportFeatureDectection(t) ?
if runtime.GOARCH == "arm64" {
switch runtime.GOOS {
- case "linux", "android":
+ case "linux", "android", "darwin":
default:
t.Skipf("%s/%s is not supported", runtime.GOOS, runtime.GOARCH)
}
@@ -38,10 +38,7 @@ func MustHaveDebugOptionsSupport(t *testing.T) {
}
func MustSupportFeatureDectection(t *testing.T) {
- if runtime.GOOS == "darwin" && runtime.GOARCH == "arm64" {
- t.Skipf("CPU feature detection is not supported on %s/%s", runtime.GOOS, runtime.GOARCH)
- }
- // TODO: maybe there are other platforms?
+ // TODO: add platforms that do not have CPU feature detection support.
}
func runDebugOptionsTest(t *testing.T, test string, options string) {