diff options
author | Martin Möhrmann <moehrmann@google.com> | 2020-10-13 22:30:23 +0200 |
---|---|---|
committer | Martin Möhrmann <moehrmann@google.com> | 2020-10-20 11:09:52 +0000 |
commit | de932da453f68b8fc04e9c2ab25136748173c806 (patch) | |
tree | d657dab40079de391135dffc4fab9fc159a1d005 | |
parent | 55b2d479d774d9887a6ec32b34e2c413f7c84f78 (diff) | |
download | go-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.go | 7 | ||||
-rw-r--r-- | src/internal/cpu/cpu_arm64.go | 73 | ||||
-rw-r--r-- | src/internal/cpu/cpu_arm64.s | 12 | ||||
-rw-r--r-- | src/internal/cpu/cpu_freebsd.go | 7 | ||||
-rw-r--r-- | src/internal/cpu/cpu_linux.go | 9 | ||||
-rw-r--r-- | src/internal/cpu/cpu_other.go | 11 | ||||
-rw-r--r-- | src/runtime/auxv_none.go | 1 | ||||
-rw-r--r-- | src/runtime/os_freebsd_arm64.go | 143 | ||||
-rw-r--r-- | src/runtime/os_freebsd_noauxv.go | 2 | ||||
-rw-r--r-- | src/runtime/os_linux_arm64.go | 14 | ||||
-rw-r--r-- | src/runtime/os_netbsd.go | 1 | ||||
-rw-r--r-- | src/runtime/os_netbsd_386.go | 3 | ||||
-rw-r--r-- | src/runtime/os_netbsd_amd64.go | 3 | ||||
-rw-r--r-- | src/runtime/os_netbsd_arm.go | 3 | ||||
-rw-r--r-- | src/runtime/os_netbsd_arm64.go | 12 | ||||
-rw-r--r-- | src/runtime/os_openbsd_arm64.go | 11 | ||||
-rw-r--r-- | src/runtime/sys_freebsd_arm64.s | 21 |
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 |