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	HasETF3Enhanced 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	HasVX           bool // vector facility. Note: the runtime sets this when it processes auxv records.
129	HasVE1          bool // vector-enhancement 1
130	_               CacheLinePad
131}
132
133// Initialize examines the processor and sets the relevant variables above.
134// This is called by the runtime package early in program initialization,
135// before normal init functions are run. env is set by runtime if the OS supports
136// cpu feature options in GODEBUG.
137func Initialize(env string) {
138	doinit()
139	processOptions(env)
140}
141
142// options contains the cpu debug options that can be used in GODEBUG.
143// Options are arch dependent and are added by the arch specific doinit functions.
144// Features that are mandatory for the specific GOARCH should not be added to options
145// (e.g. SSE2 on amd64).
146var options []option
147
148// Option names should be lower case. e.g. avx instead of AVX.
149type option struct {
150	Name      string
151	Feature   *bool
152	Specified bool // whether feature value was specified in GODEBUG
153	Enable    bool // whether feature should be enabled
154	Required  bool // whether feature is mandatory and can not be disabled
155}
156
157// processOptions enables or disables CPU feature values based on the parsed env string.
158// The env string is expected to be of the form cpu.feature1=value1,cpu.feature2=value2...
159// where feature names is one of the architecture specifc list stored in the
160// cpu packages options variable and values are either 'on' or 'off'.
161// If env contains cpu.all=off then all cpu features referenced through the options
162// variable are disabled. Other feature names and values result in warning messages.
163func processOptions(env string) {
164field:
165	for env != "" {
166		field := ""
167		i := indexByte(env, ',')
168		if i < 0 {
169			field, env = env, ""
170		} else {
171			field, env = env[:i], env[i+1:]
172		}
173		if len(field) < 4 || field[:4] != "cpu." {
174			continue
175		}
176		i = indexByte(field, '=')
177		if i < 0 {
178			print("GODEBUG: no value specified for \"", field, "\"\n")
179			continue
180		}
181		key, value := field[4:i], field[i+1:] // e.g. "SSE2", "on"
182
183		var enable bool
184		switch value {
185		case "on":
186			enable = true
187		case "off":
188			enable = false
189		default:
190			print("GODEBUG: value \"", value, "\" not supported for cpu option \"", key, "\"\n")
191			continue field
192		}
193
194		if key == "all" {
195			for i := range options {
196				options[i].Specified = true
197				options[i].Enable = enable || options[i].Required
198			}
199			continue field
200		}
201
202		for i := range options {
203			if options[i].Name == key {
204				options[i].Specified = true
205				options[i].Enable = enable
206				continue field
207			}
208		}
209
210		print("GODEBUG: unknown cpu feature \"", key, "\"\n")
211	}
212
213	for _, o := range options {
214		if !o.Specified {
215			continue
216		}
217
218		if o.Enable && !*o.Feature {
219			print("GODEBUG: can not enable \"", o.Name, "\", missing CPU support\n")
220			continue
221		}
222
223		if !o.Enable && o.Required {
224			print("GODEBUG: can not disable \"", o.Name, "\", required CPU feature\n")
225			continue
226		}
227
228		*o.Feature = o.Enable
229	}
230}
231
232// indexByte returns the index of the first instance of c in s,
233// or -1 if c is not present in s.
234func indexByte(s string, c byte) int {
235	for i := 0; i < len(s); i++ {
236		if s[i] == c {
237			return i
238		}
239	}
240	return -1
241}
242