-
Notifications
You must be signed in to change notification settings - Fork 17.8k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
cpu: support reading arm64 CPU feature registers
This allows to detect ARM64 CPU features on non-Linux systems. On Linux, this is used in case /proc/self/auxv cannot be read. Change-Id: I67d55e989f2beda0c05a97ca5e55781840a8e01c Reviewed-on: https://go-review.googlesource.com/c/sys/+/209478 Run-TryBot: Tobias Klauser <tobias.klauser@gmail.com> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Ian Lance Taylor <iant@golang.org>
- Loading branch information
Showing
11 changed files
with
253 additions
and
50 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,134 @@ | ||
// Copyright 2019 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 | ||
|
||
import "runtime" | ||
|
||
const cacheLineSize = 64 | ||
|
||
func init() { | ||
switch runtime.GOOS { | ||
case "darwin": | ||
// iOS does not seem to allow reading these registers | ||
case "android", "linux": | ||
doinit() | ||
default: | ||
readARM64Registers() | ||
} | ||
} | ||
|
||
func readARM64Registers() { | ||
Initialized = true | ||
|
||
// ID_AA64ISAR0_EL1 | ||
isar0 := getisar0() | ||
|
||
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: | ||
ARM64.HasSHA2 = true | ||
case 2: | ||
ARM64.HasSHA2 = true | ||
ARM64.HasSHA512 = true | ||
} | ||
|
||
switch extractBits(isar0, 16, 19) { | ||
case 1: | ||
ARM64.HasCRC32 = true | ||
} | ||
|
||
switch extractBits(isar0, 20, 23) { | ||
case 2: | ||
ARM64.HasATOMICS = true | ||
} | ||
|
||
switch extractBits(isar0, 28, 31) { | ||
case 1: | ||
ARM64.HasASIMDRDM = true | ||
} | ||
|
||
switch extractBits(isar0, 32, 35) { | ||
case 1: | ||
ARM64.HasSHA3 = true | ||
} | ||
|
||
switch extractBits(isar0, 36, 39) { | ||
case 1: | ||
ARM64.HasSM3 = true | ||
} | ||
|
||
switch extractBits(isar0, 40, 43) { | ||
case 1: | ||
ARM64.HasSM4 = true | ||
} | ||
|
||
switch extractBits(isar0, 44, 47) { | ||
case 1: | ||
ARM64.HasASIMDDP = true | ||
} | ||
|
||
// ID_AA64ISAR1_EL1 | ||
isar1 := getisar1() | ||
|
||
switch extractBits(isar1, 0, 3) { | ||
case 1: | ||
ARM64.HasDCPOP = true | ||
} | ||
|
||
switch extractBits(isar1, 12, 15) { | ||
case 1: | ||
ARM64.HasJSCVT = true | ||
} | ||
|
||
switch extractBits(isar1, 16, 19) { | ||
case 1: | ||
ARM64.HasFCMA = true | ||
} | ||
|
||
switch extractBits(isar1, 20, 23) { | ||
case 1: | ||
ARM64.HasLRCPC = true | ||
} | ||
|
||
// ID_AA64PFR0_EL1 | ||
pfr0 := getpfr0() | ||
|
||
switch extractBits(pfr0, 16, 19) { | ||
case 0: | ||
ARM64.HasFP = true | ||
case 1: | ||
ARM64.HasFP = true | ||
ARM64.HasFPHP = true | ||
} | ||
|
||
switch extractBits(pfr0, 20, 23) { | ||
case 0: | ||
ARM64.HasASIMD = true | ||
case 1: | ||
ARM64.HasASIMD = true | ||
ARM64.HasASIMDHP = true | ||
} | ||
|
||
switch extractBits(pfr0, 32, 35) { | ||
case 1: | ||
ARM64.HasSVE = true | ||
} | ||
} | ||
|
||
func extractBits(data uint64, start, end uint) uint { | ||
return (uint)(data>>start) & ((1 << (end - start + 1)) - 1) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
// Copyright 2019 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 !gccgo | ||
|
||
#include "textflag.h" | ||
|
||
// func getisar0() uint64 | ||
TEXT ·getisar0(SB),NOSPLIT,$0-8 | ||
// get Instruction Set Attributes 0 into x0 | ||
// mrs x0, ID_AA64ISAR0_EL1 = d5380600 | ||
WORD $0xd5380600 | ||
MOVD R0, ret+0(FP) | ||
RET | ||
|
||
// func getisar1() uint64 | ||
TEXT ·getisar1(SB),NOSPLIT,$0-8 | ||
// get Instruction Set Attributes 1 into x0 | ||
// mrs x0, ID_AA64ISAR1_EL1 = d5380620 | ||
WORD $0xd5380620 | ||
MOVD R0, ret+0(FP) | ||
RET | ||
|
||
// func getpfr0() uint64 | ||
TEXT ·getpfr0(SB),NOSPLIT,$0-8 | ||
// get Processor Feature Register 0 into x0 | ||
// mrs x0, ID_AA64PFR0_EL1 = d5380400 | ||
WORD $0xd5380400 | ||
MOVD R0, ret+0(FP) | ||
RET |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
// Copyright 2019 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 !gccgo | ||
|
||
package cpu | ||
|
||
func getisar0() uint64 | ||
func getisar1() uint64 | ||
func getpfr0() uint64 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
// Copyright 2019 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 gccgo | ||
|
||
package cpu | ||
|
||
func getisar0() uint64 { return 0 } | ||
func getisar1() uint64 { return 0 } | ||
func getpfr0() uint64 { return 0 } |
File renamed without changes.
File renamed without changes.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -6,4 +6,4 @@ | |
|
||
package cpu | ||
|
||
const cacheLineSize = 64 | ||
func doinit() {} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
// Copyright 2019 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 | ||
|
||
import ( | ||
"io/ioutil" | ||
) | ||
|
||
const ( | ||
_AT_HWCAP = 16 | ||
_AT_HWCAP2 = 26 | ||
|
||
procAuxv = "/proc/self/auxv" | ||
|
||
uintSize = int(32 << (^uint(0) >> 63)) | ||
) | ||
|
||
// For those platforms don't have a 'cpuid' equivalent we use HWCAP/HWCAP2 | ||
// These are initialized in cpu_$GOARCH.go | ||
// and should not be changed after they are initialized. | ||
var hwCap uint | ||
var hwCap2 uint | ||
|
||
func readHWCAP() error { | ||
buf, err := ioutil.ReadFile(procAuxv) | ||
if err != nil { | ||
// e.g. on android /proc/self/auxv is not accessible, so silently | ||
// ignore the error and leave Initialized = false. On some | ||
// architectures (e.g. arm64) doinit() implements a fallback | ||
// readout and will set Initialized = true again. | ||
return err | ||
} | ||
bo := hostByteOrder() | ||
for len(buf) >= 2*(uintSize/8) { | ||
var tag, val uint | ||
switch uintSize { | ||
case 32: | ||
tag = uint(bo.Uint32(buf[0:])) | ||
val = uint(bo.Uint32(buf[4:])) | ||
buf = buf[8:] | ||
case 64: | ||
tag = uint(bo.Uint64(buf[0:])) | ||
val = uint(bo.Uint64(buf[8:])) | ||
buf = buf[16:] | ||
} | ||
switch tag { | ||
case _AT_HWCAP: | ||
hwCap = val | ||
case _AT_HWCAP2: | ||
hwCap2 = val | ||
} | ||
} | ||
return nil | ||
} |