1// Copyright 2017 The Go Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style
3// license that can be found in the LICENSE file.
4
5// Package cpu implements processor feature detection
6// used by the Go standard library.
7package cpu
8
9// DebugOptions is set to true by the runtime if the OS supports reading
10// GODEBUG early in runtime startup.
11// This should not be changed after it is initialized.
12var DebugOptions bool
13
14// CacheLinePad is used to pad structs to avoid false sharing.
15type CacheLinePad struct{ _ [CacheLinePadSize]byte }
16
17// CacheLineSize is the CPU's assumed cache line size.
18// There is currently no runtime detection of the real cache line size
19// so we use the constant per GOARCH CacheLinePadSize as an approximation.
20var CacheLineSize uintptr = CacheLinePadSize
21
22var X86 x86
23
24// The booleans in x86 contain the correspondingly named cpuid feature bit.
25// HasAVX and HasAVX2 are only set if the OS does support XMM and YMM registers
26// in addition to the cpuid feature bit being set.
27// The struct is padded to avoid false sharing.
28type x86 struct {
29	_            CacheLinePad
30	HasAES       bool
31	HasADX       bool
32	HasAVX       bool
33	HasAVX2      bool
34	HasBMI1      bool
35	HasBMI2      bool
36	HasERMS      bool
37	HasFMA       bool
38	HasOSXSAVE   bool
39	HasPCLMULQDQ bool
40	HasPOPCNT    bool
41	HasSSE2      bool
42	HasSSE3      bool
43	HasSSSE3     bool
44	HasSSE41     bool
45	HasSSE42     bool
46	_            CacheLinePad
47}
48
49var PPC64 ppc64
50
51// For ppc64(le), it is safe to check only for ISA level starting on ISA v3.00,
52// since there are no optional categories. There are some exceptions that also
53// require kernel support to work (darn, scv), so there are feature bits for
54// those as well. The minimum processor requirement is POWER8 (ISA 2.07).
55// The struct is padded to avoid false sharing.
56type ppc64 struct {
57	_        CacheLinePad
58	HasDARN  bool // Hardware random number generator (requires kernel enablement)
59	HasSCV   bool // Syscall vectored (requires kernel enablement)
60	IsPOWER8 bool // ISA v2.07 (POWER8)
61	IsPOWER9 bool // ISA v3.00 (POWER9)
62	_        CacheLinePad
63}
64
65var ARM arm
66
67// The booleans in arm contain the correspondingly named cpu feature bit.
68// The struct is padded to avoid false sharing.
69type arm struct {
70	_        CacheLinePad
71	HasVFPv4 bool
72	HasIDIVA bool
73	_        CacheLinePad
74}
75
76var ARM64 arm64
77
78// The booleans in arm64 contain the correspondingly named cpu feature bit.
79// The struct is padded to avoid false sharing.
80type arm64 struct {
81	_           CacheLinePad
82	HasFP       bool
83	HasASIMD    bool
84	HasEVTSTRM  bool
85	HasAES      bool
86	HasPMULL    bool
87	HasSHA1     bool
88	HasSHA2     bool
89	HasCRC32    bool
90	HasATOMICS  bool
91	HasFPHP     bool
92	HasASIMDHP  bool
93	HasCPUID    bool
94	HasASIMDRDM bool
95	HasJSCVT    bool
96	HasFCMA     bool
97	HasLRCPC    bool
98	HasDCPOP    bool
99	HasSHA3     bool
100	HasSM3      bool
101	HasSM4      bool
102	HasASIMDDP  bool
103	HasSHA512   bool
104	HasSVE      bool
105	HasASIMDFHM bool
106	_           CacheLinePad
107}
108
109var S390X s390x
110
111type s390x struct {
112	_         CacheLinePad
113	HasZARCH  bool // z architecture mode is active [mandatory]
114	HasSTFLE  bool // store facility list extended [mandatory]
115	HasLDISP  bool // long (20-bit) displacements [mandatory]
116	HasEIMM   bool // 32-bit immediates [mandatory]
117	HasDFP    bool // decimal floating point
118	HasETF3EH bool // ETF-3 enhanced
119	HasMSA    bool // message security assist (CPACF)
120	HasAES    bool // KM-AES{128,192,256} functions
121	HasAESCBC bool // KMC-AES{128,192,256} functions
122	HasAESCTR bool // KMCTR-AES{128,192,256} functions
123	HasAESGCM bool // KMA-GCM-AES{128,192,256} functions
124	HasGHASH  bool // KIMD-GHASH function
125	HasSHA1   bool // K{I,L}MD-SHA-1 functions
126	HasSHA256 bool // K{I,L}MD-SHA-256 functions
127	HasSHA512 bool // K{I,L}MD-SHA-512 functions
128	HasSHA3   bool // K{I,L}MD-SHA3-{224,256,384,512} and K{I,L}MD-SHAKE-{128,256} functions
129	HasVX     bool // vector facility. Note: the runtime sets this when it processes auxv records.
130	HasVXE    bool // vector-enhancements facility 1
131	HasKDSA   bool // elliptic curve functions
132	HasECDSA  bool // NIST curves
133	HasEDDSA  bool // Edwards curves
134	_         CacheLinePad
135}
136
137// Initialize examines the processor and sets the relevant variables above.
138// This is called by the runtime package early in program initialization,
139// before normal init functions are run. env is set by runtime if the OS supports
140// cpu feature options in GODEBUG.
141func Initialize(env string) {
142	doinit()
143	processOptions(env)
144}
145
146// options contains the cpu debug options that can be used in GODEBUG.
147// Options are arch dependent and are added by the arch specific doinit functions.
148// Features that are mandatory for the specific GOARCH should not be added to options
149// (e.g. SSE2 on amd64).
150var options []option
151
152// Option names should be lower case. e.g. avx instead of AVX.
153type option struct {
154	Name      string
155	Feature   *bool
156	Specified bool // whether feature value was specified in GODEBUG
157	Enable    bool // whether feature should be enabled
158	Required  bool // whether feature is mandatory and can not be disabled
159}
160
161// processOptions enables or disables CPU feature values based on the parsed env string.
162// The env string is expected to be of the form cpu.feature1=value1,cpu.feature2=value2...
163// where feature names is one of the architecture specific list stored in the
164// cpu packages options variable and values are either 'on' or 'off'.
165// If env contains cpu.all=off then all cpu features referenced through the options
166// variable are disabled. Other feature names and values result in warning messages.
167func processOptions(env string) {
168field:
169	for env != "" {
170		field := ""
171		i := indexByte(env, ',')
172		if i < 0 {
173			field, env = env, ""
174		} else {
175			field, env = env[:i], env[i+1:]
176		}
177		if len(field) < 4 || field[:4] != "cpu." {
178			continue
179		}
180		i = indexByte(field, '=')
181		if i < 0 {
182			print("GODEBUG: no value specified for \"", field, "\"\n")
183			continue
184		}
185		key, value := field[4:i], field[i+1:] // e.g. "SSE2", "on"
186
187		var enable bool
188		switch value {
189		case "on":
190			enable = true
191		case "off":
192			enable = false
193		default:
194			print("GODEBUG: value \"", value, "\" not supported for cpu option \"", key, "\"\n")
195			continue field
196		}
197
198		if key == "all" {
199			for i := range options {
200				options[i].Specified = true
201				options[i].Enable = enable || options[i].Required
202			}
203			continue field
204		}
205
206		for i := range options {
207			if options[i].Name == key {
208				options[i].Specified = true
209				options[i].Enable = enable
210				continue field
211			}
212		}
213
214		print("GODEBUG: unknown cpu feature \"", key, "\"\n")
215	}
216
217	for _, o := range options {
218		if !o.Specified {
219			continue
220		}
221
222		if o.Enable && !*o.Feature {
223			print("GODEBUG: can not enable \"", o.Name, "\", missing CPU support\n")
224			continue
225		}
226
227		if !o.Enable && o.Required {
228			print("GODEBUG: can not disable \"", o.Name, "\", required CPU feature\n")
229			continue
230		}
231
232		*o.Feature = o.Enable
233	}
234}
235
236// indexByte returns the index of the first instance of c in s,
237// or -1 if c is not present in s.
238func indexByte(s string, c byte) int {
239	for i := 0; i < len(s); i++ {
240		if s[i] == c {
241			return i
242		}
243	}
244	return -1
245}
246