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}