aboutsummaryrefslogtreecommitdiff
path: root/src/internal/cpu
diff options
context:
space:
mode:
Diffstat (limited to 'src/internal/cpu')
-rw-r--r--src/internal/cpu/cpu_android.go7
-rw-r--r--src/internal/cpu/cpu_arm64.go141
-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_mips.go3
-rw-r--r--src/internal/cpu/cpu_mipsle.go3
-rw-r--r--src/internal/cpu/cpu_no_init.go18
-rw-r--r--src/internal/cpu/cpu_no_name.go19
-rw-r--r--src/internal/cpu/cpu_other.go11
-rw-r--r--src/internal/cpu/cpu_riscv64.go3
-rw-r--r--src/internal/cpu/cpu_s390x.go15
-rw-r--r--src/internal/cpu/cpu_test.go9
-rw-r--r--src/internal/cpu/cpu_wasm.go3
-rw-r--r--src/internal/cpu/cpu_x86.go49
15 files changed, 215 insertions, 94 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 efdb3b9e33..533bea2470 100644
--- a/src/internal/cpu/cpu_arm64.go
+++ b/src/internal/cpu/cpu_arm64.go
@@ -6,97 +6,90 @@ 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_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
+ hwcap_AES = 1 << 3
+ hwcap_PMULL = 1 << 4
+ hwcap_SHA1 = 1 << 5
+ hwcap_SHA2 = 1 << 6
+ hwcap_CRC32 = 1 << 7
+ hwcap_ATOMICS = 1 << 8
)
func doinit() {
options = []option{
- {Name: "evtstrm", Feature: &ARM64.HasEVTSTRM},
{Name: "aes", Feature: &ARM64.HasAES},
{Name: "pmull", Feature: &ARM64.HasPMULL},
{Name: "sha1", Feature: &ARM64.HasSHA1},
{Name: "sha2", Feature: &ARM64.HasSHA2},
{Name: "crc32", Feature: &ARM64.HasCRC32},
{Name: "atomics", Feature: &ARM64.HasATOMICS},
- {Name: "fphp", Feature: &ARM64.HasFPHP},
- {Name: "asimdhp", Feature: &ARM64.HasASIMDHP},
- {Name: "cpuid", Feature: &ARM64.HasCPUID},
- {Name: "asimdrdm", Feature: &ARM64.HasASIMDRDM},
- {Name: "jscvt", Feature: &ARM64.HasJSCVT},
- {Name: "fcma", Feature: &ARM64.HasFCMA},
- {Name: "lrcpc", Feature: &ARM64.HasLRCPC},
- {Name: "dcpop", Feature: &ARM64.HasDCPOP},
- {Name: "sha3", Feature: &ARM64.HasSHA3},
- {Name: "sm3", Feature: &ARM64.HasSM3},
- {Name: "sm4", Feature: &ARM64.HasSM4},
- {Name: "asimddp", Feature: &ARM64.HasASIMDDP},
- {Name: "sha512", Feature: &ARM64.HasSHA512},
- {Name: "sve", Feature: &ARM64.HasSVE},
- {Name: "asimdfhm", Feature: &ARM64.HasASIMDFHM},
-
- // These capabilities should always be enabled on arm64:
- {Name: "fp", Feature: &ARM64.HasFP, Required: true},
- {Name: "asimd", Feature: &ARM64.HasASIMD, Required: true},
}
- // HWCAP feature bits
- ARM64.HasFP = isSet(HWCap, hwcap_FP)
- ARM64.HasASIMD = isSet(HWCap, hwcap_ASIMD)
- ARM64.HasEVTSTRM = isSet(HWCap, hwcap_EVTSTRM)
- 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)
- ARM64.HasFPHP = isSet(HWCap, hwcap_FPHP)
- ARM64.HasASIMDHP = isSet(HWCap, hwcap_ASIMDHP)
- ARM64.HasCPUID = isSet(HWCap, hwcap_CPUID)
- ARM64.HasASIMDRDM = isSet(HWCap, hwcap_ASIMDRDM)
- ARM64.HasJSCVT = isSet(HWCap, hwcap_JSCVT)
- ARM64.HasFCMA = isSet(HWCap, hwcap_FCMA)
- ARM64.HasLRCPC = isSet(HWCap, hwcap_LRCPC)
- ARM64.HasDCPOP = isSet(HWCap, hwcap_DCPOP)
- ARM64.HasSHA3 = isSet(HWCap, hwcap_SHA3)
- ARM64.HasSM3 = isSet(HWCap, hwcap_SM3)
- ARM64.HasSM4 = isSet(HWCap, hwcap_SM4)
- ARM64.HasASIMDDP = isSet(HWCap, hwcap_ASIMDDP)
- ARM64.HasSHA512 = isSet(HWCap, hwcap_SHA512)
- ARM64.HasSVE = isSet(HWCap, hwcap_SVE)
- ARM64.HasASIMDFHM = isSet(HWCap, hwcap_ASIMDFHM)
+ 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_mips.go b/src/internal/cpu/cpu_mips.go
index 0f821e44e7..14a9c975ea 100644
--- a/src/internal/cpu/cpu_mips.go
+++ b/src/internal/cpu/cpu_mips.go
@@ -5,3 +5,6 @@
package cpu
const CacheLinePadSize = 32
+
+func doinit() {
+}
diff --git a/src/internal/cpu/cpu_mipsle.go b/src/internal/cpu/cpu_mipsle.go
index 0f821e44e7..14a9c975ea 100644
--- a/src/internal/cpu/cpu_mipsle.go
+++ b/src/internal/cpu/cpu_mipsle.go
@@ -5,3 +5,6 @@
package cpu
const CacheLinePadSize = 32
+
+func doinit() {
+}
diff --git a/src/internal/cpu/cpu_no_init.go b/src/internal/cpu/cpu_no_init.go
deleted file mode 100644
index fb381e1ce2..0000000000
--- a/src/internal/cpu/cpu_no_init.go
+++ /dev/null
@@ -1,18 +0,0 @@
-// Copyright 2018 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 !386
-// +build !amd64
-// +build !arm
-// +build !arm64
-// +build !ppc64
-// +build !ppc64le
-// +build !s390x
-// +build !mips64
-// +build !mips64le
-
-package cpu
-
-func doinit() {
-}
diff --git a/src/internal/cpu/cpu_no_name.go b/src/internal/cpu/cpu_no_name.go
new file mode 100644
index 0000000000..ce1c37a3c7
--- /dev/null
+++ b/src/internal/cpu/cpu_no_name.go
@@ -0,0 +1,19 @@
+// 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 !386
+// +build !amd64
+
+package cpu
+
+// Name returns the CPU name given by the vendor
+// if it can be read directly from memory or by CPU instructions.
+// If the CPU name can not be determined an empty string is returned.
+//
+// Implementations that use the Operating System (e.g. sysctl or /sys/)
+// to gather CPU information for display should be placed in internal/sysinfo.
+func Name() string {
+ // "A CPU has no name".
+ return ""
+}
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/internal/cpu/cpu_riscv64.go b/src/internal/cpu/cpu_riscv64.go
index c49cab79fd..54b8c3378b 100644
--- a/src/internal/cpu/cpu_riscv64.go
+++ b/src/internal/cpu/cpu_riscv64.go
@@ -5,3 +5,6 @@
package cpu
const CacheLinePadSize = 32
+
+func doinit() {
+}
diff --git a/src/internal/cpu/cpu_s390x.go b/src/internal/cpu/cpu_s390x.go
index 526e074225..45d8ed27f0 100644
--- a/src/internal/cpu/cpu_s390x.go
+++ b/src/internal/cpu/cpu_s390x.go
@@ -6,6 +6,8 @@ package cpu
const CacheLinePadSize = 256
+var HWCap uint
+
// bitIsSet reports whether the bit at index is set. The bit index
// is in big endian order, so bit index 0 is the leftmost bit.
func bitIsSet(bits []uint64, index uint) bool {
@@ -95,8 +97,10 @@ const (
// vector facilities
vxe facility = 135 // vector-enhancements 1
- // Note: vx and highgprs are excluded because they require
- // kernel support and so must be fetched from HWCAP.
+ // Note: vx requires kernel support
+ // and so must be fetched from HWCAP.
+
+ hwcap_VX = 1 << 11 // vector facility
)
// facilityList contains the result of an STFLE call.
@@ -188,7 +192,14 @@ func doinit() {
S390X.HasEDDSA = kdsa.Has(eddsaVerifyEd25519, eddsaSignEd25519, eddsaVerifyEd448, eddsaSignEd448)
}
}
+
+ S390X.HasVX = isSet(HWCap, hwcap_VX)
+
if S390X.HasVX {
S390X.HasVXE = facilities.Has(vxe)
}
}
+
+func isSet(hwc uint, value uint) bool {
+ return hwc&value != 0
+}
diff --git a/src/internal/cpu/cpu_test.go b/src/internal/cpu/cpu_test.go
index e09bd2d8b9..919bbd5ed7 100644
--- a/src/internal/cpu/cpu_test.go
+++ b/src/internal/cpu/cpu_test.go
@@ -15,6 +15,7 @@ import (
)
func TestMinimalFeatures(t *testing.T) {
+ // TODO: maybe do MustSupportFeatureDectection(t) ?
if runtime.GOARCH == "arm64" {
switch runtime.GOOS {
case "linux", "android":
@@ -36,6 +37,13 @@ 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?
+}
+
func runDebugOptionsTest(t *testing.T, test string, options string) {
MustHaveDebugOptionsSupport(t)
@@ -58,6 +66,7 @@ func runDebugOptionsTest(t *testing.T, test string, options string) {
}
func TestDisableAllCapabilities(t *testing.T) {
+ MustSupportFeatureDectection(t)
runDebugOptionsTest(t, "TestAllCapabilitiesDisabled", "cpu.all=off")
}
diff --git a/src/internal/cpu/cpu_wasm.go b/src/internal/cpu/cpu_wasm.go
index b459738770..2310ad6a48 100644
--- a/src/internal/cpu/cpu_wasm.go
+++ b/src/internal/cpu/cpu_wasm.go
@@ -5,3 +5,6 @@
package cpu
const CacheLinePadSize = 64
+
+func doinit() {
+}
diff --git a/src/internal/cpu/cpu_x86.go b/src/internal/cpu/cpu_x86.go
index da6cf67258..fb414adaf8 100644
--- a/src/internal/cpu/cpu_x86.go
+++ b/src/internal/cpu/cpu_x86.go
@@ -38,6 +38,8 @@ const (
cpuid_ADX = 1 << 19
)
+var maxExtendedFunctionInformation uint32
+
func doinit() {
options = []option{
{Name: "adx", Feature: &X86.HasADX},
@@ -65,6 +67,8 @@ func doinit() {
return
}
+ maxExtendedFunctionInformation, _, _, _ = cpuid(0x80000000, 0)
+
_, _, ecx1, edx1 := cpuid(1, 0)
X86.HasSSE2 = isSet(edx1, cpuid_SSE2)
@@ -103,3 +107,48 @@ func doinit() {
func isSet(hwc uint32, value uint32) bool {
return hwc&value != 0
}
+
+// Name returns the CPU name given by the vendor.
+// If the CPU name can not be determined an
+// empty string is returned.
+func Name() string {
+ if maxExtendedFunctionInformation < 0x80000004 {
+ return ""
+ }
+
+ data := make([]byte, 0, 3*4*4)
+
+ var eax, ebx, ecx, edx uint32
+ eax, ebx, ecx, edx = cpuid(0x80000002, 0)
+ data = appendBytes(data, eax, ebx, ecx, edx)
+ eax, ebx, ecx, edx = cpuid(0x80000003, 0)
+ data = appendBytes(data, eax, ebx, ecx, edx)
+ eax, ebx, ecx, edx = cpuid(0x80000004, 0)
+ data = appendBytes(data, eax, ebx, ecx, edx)
+
+ // Trim leading spaces.
+ for len(data) > 0 && data[0] == ' ' {
+ data = data[1:]
+ }
+
+ // Trim tail after and including the first null byte.
+ for i, c := range data {
+ if c == '\x00' {
+ data = data[:i]
+ break
+ }
+ }
+
+ return string(data)
+}
+
+func appendBytes(b []byte, args ...uint32) []byte {
+ for _, arg := range args {
+ b = append(b,
+ byte((arg >> 0)),
+ byte((arg >> 8)),
+ byte((arg >> 16)),
+ byte((arg >> 24)))
+ }
+ return b
+}