1// Copyright (c) 2020 Klaus Post, released under MIT License. See LICENSE file.
2
3// Copyright 2018 The Go Authors. All rights reserved.
4// Use of this source code is governed by a BSD-style
5// license that can be found in the LICENSE file located
6// here https://github.com/golang/sys/blob/master/LICENSE
7
8package cpuid
9
10import (
11 "encoding/binary"
12 "io/ioutil"
13 "runtime"
14)
15
16// HWCAP bits.
17const (
18 hwcap_FP = 1 << 0
19 hwcap_ASIMD = 1 << 1
20 hwcap_EVTSTRM = 1 << 2
21 hwcap_AES = 1 << 3
22 hwcap_PMULL = 1 << 4
23 hwcap_SHA1 = 1 << 5
24 hwcap_SHA2 = 1 << 6
25 hwcap_CRC32 = 1 << 7
26 hwcap_ATOMICS = 1 << 8
27 hwcap_FPHP = 1 << 9
28 hwcap_ASIMDHP = 1 << 10
29 hwcap_CPUID = 1 << 11
30 hwcap_ASIMDRDM = 1 << 12
31 hwcap_JSCVT = 1 << 13
32 hwcap_FCMA = 1 << 14
33 hwcap_LRCPC = 1 << 15
34 hwcap_DCPOP = 1 << 16
35 hwcap_SHA3 = 1 << 17
36 hwcap_SM3 = 1 << 18
37 hwcap_SM4 = 1 << 19
38 hwcap_ASIMDDP = 1 << 20
39 hwcap_SHA512 = 1 << 21
40 hwcap_SVE = 1 << 22
41 hwcap_ASIMDFHM = 1 << 23
42 hwcap_DIT = 1 << 24
43 hwcap_USCAT = 1 << 25
44 hwcap_ILRCPC = 1 << 26
45 hwcap_FLAGM = 1 << 27
46 hwcap_SSBS = 1 << 28
47 hwcap_SB = 1 << 29
48 hwcap_PACA = 1 << 30
49 hwcap_PACG = 1 << 31
50 hwcap_GCS = 1 << 32
51
52 hwcap2_DCPODP = 1 << 0
53 hwcap2_SVE2 = 1 << 1
54 hwcap2_SVEAES = 1 << 2
55 hwcap2_SVEPMULL = 1 << 3
56 hwcap2_SVEBITPERM = 1 << 4
57 hwcap2_SVESHA3 = 1 << 5
58 hwcap2_SVESM4 = 1 << 6
59 hwcap2_FLAGM2 = 1 << 7
60 hwcap2_FRINT = 1 << 8
61 hwcap2_SVEI8MM = 1 << 9
62 hwcap2_SVEF32MM = 1 << 10
63 hwcap2_SVEF64MM = 1 << 11
64 hwcap2_SVEBF16 = 1 << 12
65 hwcap2_I8MM = 1 << 13
66 hwcap2_BF16 = 1 << 14
67 hwcap2_DGH = 1 << 15
68 hwcap2_RNG = 1 << 16
69 hwcap2_BTI = 1 << 17
70 hwcap2_MTE = 1 << 18
71 hwcap2_ECV = 1 << 19
72 hwcap2_AFP = 1 << 20
73 hwcap2_RPRES = 1 << 21
74 hwcap2_MTE3 = 1 << 22
75 hwcap2_SME = 1 << 23
76 hwcap2_SME_I16I64 = 1 << 24
77 hwcap2_SME_F64F64 = 1 << 25
78 hwcap2_SME_I8I32 = 1 << 26
79 hwcap2_SME_F16F32 = 1 << 27
80 hwcap2_SME_B16F32 = 1 << 28
81 hwcap2_SME_F32F32 = 1 << 29
82 hwcap2_SME_FA64 = 1 << 30
83 hwcap2_WFXT = 1 << 31
84 hwcap2_EBF16 = 1 << 32
85 hwcap2_SVE_EBF16 = 1 << 33
86 hwcap2_CSSC = 1 << 34
87 hwcap2_RPRFM = 1 << 35
88 hwcap2_SVE2P1 = 1 << 36
89 hwcap2_SME2 = 1 << 37
90 hwcap2_SME2P1 = 1 << 38
91 hwcap2_SME_I16I32 = 1 << 39
92 hwcap2_SME_BI32I32 = 1 << 40
93 hwcap2_SME_B16B16 = 1 << 41
94 hwcap2_SME_F16F16 = 1 << 42
95 hwcap2_MOPS = 1 << 43
96 hwcap2_HBC = 1 << 44
97 hwcap2_SVE_B16B16 = 1 << 45
98 hwcap2_LRCPC3 = 1 << 46
99 hwcap2_LSE128 = 1 << 47
100 hwcap2_FPMR = 1 << 48
101 hwcap2_LUT = 1 << 49
102 hwcap2_FAMINMAX = 1 << 50
103 hwcap2_F8CVT = 1 << 51
104 hwcap2_F8FMA = 1 << 52
105 hwcap2_F8DP4 = 1 << 53
106 hwcap2_F8DP2 = 1 << 54
107 hwcap2_F8E4M3 = 1 << 55
108 hwcap2_F8E5M2 = 1 << 56
109 hwcap2_SME_LUTV2 = 1 << 57
110 hwcap2_SME_F8F16 = 1 << 58
111 hwcap2_SME_F8F32 = 1 << 59
112 hwcap2_SME_SF8FMA = 1 << 60
113 hwcap2_SME_SF8DP4 = 1 << 61
114 hwcap2_SME_SF8DP2 = 1 << 62
115 hwcap2_POE = 1 << 63
116)
117
118func detectOS(c *CPUInfo) bool {
119 // For now assuming no hyperthreading is reasonable.
120 c.LogicalCores = runtime.NumCPU()
121 c.PhysicalCores = c.LogicalCores
122 c.ThreadsPerCore = 1
123 if hwcap == 0 {
124 // We did not get values from the runtime.
125 // Try reading /proc/self/auxv
126
127 // From https://github.com/golang/sys
128 const (
129 _AT_HWCAP = 16
130 _AT_HWCAP2 = 26
131
132 uintSize = int(32 << (^uint(0) >> 63))
133 )
134
135 buf, err := ioutil.ReadFile("/proc/self/auxv")
136 if err != nil {
137 // e.g. on android /proc/self/auxv is not accessible, so silently
138 // ignore the error and leave Initialized = false. On some
139 // architectures (e.g. arm64) doinit() implements a fallback
140 // readout and will set Initialized = true again.
141 return false
142 }
143 bo := binary.LittleEndian
144 for len(buf) >= 2*(uintSize/8) {
145 var tag, val uint
146 switch uintSize {
147 case 32:
148 tag = uint(bo.Uint32(buf[0:]))
149 val = uint(bo.Uint32(buf[4:]))
150 buf = buf[8:]
151 case 64:
152 tag = uint(bo.Uint64(buf[0:]))
153 val = uint(bo.Uint64(buf[8:]))
154 buf = buf[16:]
155 }
156 switch tag {
157 case _AT_HWCAP:
158 hwcap = val
159 case _AT_HWCAP2:
160 // Not used
161 }
162 }
163 if hwcap == 0 {
164 return false
165 }
166 }
167
168 // HWCap was populated by the runtime from the auxiliary vector.
169 // Use HWCap information since reading aarch64 system registers
170 // is not supported in user space on older linux kernels.
171 c.featureSet.setIf(isSet(hwcap, hwcap_AES), AESARM)
172 c.featureSet.setIf(isSet(hwcap, hwcap_ASIMD), ASIMD)
173 c.featureSet.setIf(isSet(hwcap, hwcap_ASIMDDP), ASIMDDP)
174 c.featureSet.setIf(isSet(hwcap, hwcap_ASIMDHP), ASIMDHP)
175 c.featureSet.setIf(isSet(hwcap, hwcap_ASIMDRDM), ASIMDRDM)
176 c.featureSet.setIf(isSet(hwcap, hwcap_CPUID), ARMCPUID)
177 c.featureSet.setIf(isSet(hwcap, hwcap_CRC32), CRC32)
178 c.featureSet.setIf(isSet(hwcap, hwcap_DCPOP), DCPOP)
179 c.featureSet.setIf(isSet(hwcap, hwcap_EVTSTRM), EVTSTRM)
180 c.featureSet.setIf(isSet(hwcap, hwcap_FCMA), FCMA)
181 c.featureSet.setIf(isSet(hwcap, hwcap_ASIMDFHM), FHM)
182 c.featureSet.setIf(isSet(hwcap, hwcap_FP), FP)
183 c.featureSet.setIf(isSet(hwcap, hwcap_FPHP), FPHP)
184 c.featureSet.setIf(isSet(hwcap, hwcap_JSCVT), JSCVT)
185 c.featureSet.setIf(isSet(hwcap, hwcap_LRCPC), LRCPC)
186 c.featureSet.setIf(isSet(hwcap, hwcap_PMULL), PMULL)
187 c.featureSet.setIf(isSet(hwcap, hwcap2_RNG), RNDR)
188 // c.featureSet.setIf(isSet(hwcap, hwcap_), TLB)
189 // c.featureSet.setIf(isSet(hwcap, hwcap_), TS)
190 c.featureSet.setIf(isSet(hwcap, hwcap_SHA1), SHA1)
191 c.featureSet.setIf(isSet(hwcap, hwcap_SHA2), SHA2)
192 c.featureSet.setIf(isSet(hwcap, hwcap_SHA3), SHA3)
193 c.featureSet.setIf(isSet(hwcap, hwcap_SHA512), SHA512)
194 c.featureSet.setIf(isSet(hwcap, hwcap_SM3), SM3)
195 c.featureSet.setIf(isSet(hwcap, hwcap_SM4), SM4)
196 c.featureSet.setIf(isSet(hwcap, hwcap_SVE), SVE)
197
198 // The Samsung S9+ kernel reports support for atomics, but not all cores
199 // actually support them, resulting in SIGILL. See issue #28431.
200 // TODO(elias.naur): Only disable the optimization on bad chipsets on android.
201 c.featureSet.setIf(isSet(hwcap, hwcap_ATOMICS) && runtime.GOOS != "android", ATOMICS)
202
203 return true
204}
205
206func isSet(hwc uint, value uint) bool {
207 return hwc&value != 0
208}