aboutsummaryrefslogtreecommitdiff
path: root/src/internal/cpu/cpu_arm64.go
blob: 533bea247009faaf3fa86ce513333fecece2967d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
// Copyright 2017 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 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
)

func doinit() {
	options = []option{
		{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},
	}

	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