]> Cypherpunks repositories - gostls13.git/commitdiff
internal/cpu: consolidate arm64 feature detection
authorMartin Möhrmann <moehrmann@google.com>
Tue, 13 Oct 2020 20:30:23 +0000 (22:30 +0200)
committerMartin Möhrmann <moehrmann@google.com>
Tue, 20 Oct 2020 11:09:52 +0000 (11:09 +0000)
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>
17 files changed:
src/internal/cpu/cpu_android.go [new file with mode: 0644]
src/internal/cpu/cpu_arm64.go
src/internal/cpu/cpu_arm64.s [new file with mode: 0644]
src/internal/cpu/cpu_freebsd.go [new file with mode: 0644]
src/internal/cpu/cpu_linux.go [new file with mode: 0644]
src/internal/cpu/cpu_other.go [new file with mode: 0644]
src/runtime/auxv_none.go
src/runtime/os_freebsd_arm64.go
src/runtime/os_freebsd_noauxv.go
src/runtime/os_linux_arm64.go
src/runtime/os_netbsd.go
src/runtime/os_netbsd_386.go
src/runtime/os_netbsd_amd64.go
src/runtime/os_netbsd_arm.go
src/runtime/os_netbsd_arm64.go
src/runtime/os_openbsd_arm64.go
src/runtime/sys_freebsd_arm64.s

diff --git a/src/internal/cpu/cpu_android.go b/src/internal/cpu/cpu_android.go
new file mode 100644 (file)
index 0000000..d995e8d
--- /dev/null
@@ -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"
index d9e0c98ca6b5d67d23ee26444c31b19f89a925c8..533bea247009faaf3fa86ce513333fecece2967d 100644 (file)
@@ -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 (file)
index 0000000..d859149
--- /dev/null
@@ -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 (file)
index 0000000..dc37173
--- /dev/null
@@ -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 (file)
index 0000000..ec0b84c
--- /dev/null
@@ -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 (file)
index 0000000..8a15fbe
--- /dev/null
@@ -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"
index 3a560a17937fc0304ef20c67b56574aa77555b98..3ca617b21eb00dfc0b701f8d993186c7035b67b3 100644 (file)
@@ -7,7 +7,6 @@
 // +build !dragonfly
 // +build !freebsd
 // +build !netbsd
-// +build !openbsd !arm64
 // +build !solaris
 
 package runtime
index 51ebf9d4784867f3778331e4dff0228064d81f53..b5b25f0dc5f8c6d985db8bfc39dfe173cecd5ad7 100644 (file)
@@ -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().
index c6a49927c8b10266cf3ecdc362586927e6d1f517..01efb9b7c9c83b2c8a374ecf88c43a136ca1f3db 100644 (file)
@@ -3,7 +3,7 @@
 // license that can be found in the LICENSE file.
 
 // +build freebsd
-// +build !arm,!arm64
+// +build !arm
 
 package runtime
 
index 19968dc164b7c63e40b4cd8f64caf56ce0c7b867..c5fd74204883e11581b81dbe2e6c1cbcfc6d0f4f 100644 (file)
@@ -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)
        }
 }
 
index c4c3d8e2fe1aa31539c6b70af1c3c47d6cd18815..f7f90cedc1a8b9eacd7bcd0feedd90bb1897d81a 100644 (file)
@@ -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 (
index c203af9cef526121b25eed338069a7445d1ceb97..037f7e36dc6ae730321f68e2b9f2c777cd49a06b 100644 (file)
@@ -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) {
-}
index ea9d125492089283910807e3824a03c19a212a20..5118b0c4ffda78c82406ef194c5575f7d445cbbe 100644 (file)
@@ -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) {
-}
index 646da9dc0b489a15565c747fc673b7a745ed35ce..b5ec23e45b0a8833154279d37920e42ad6673802 100644 (file)
@@ -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) {
-}
index ae2638c778ce9f182007076f202499edc3b11b5e..8d21b0a430f9abeecc833cf6dcb4f1e459f698b0 100644 (file)
@@ -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
-}
index d559a2a3e5adc61fae6937fe180819838e48256b..d71de7d196f3ada9a8bc5f7484126f486e977095 100644 (file)
@@ -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
-}
index 2330f2ffe2cb66496531845d7fe9482becf1b58e..8a4f9b7fa1462a024691a8e40a5895f93f8ce99b 100644 (file)
@@ -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