220 lines
6.6 KiB
Go
220 lines
6.6 KiB
Go
// 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 implements processor feature detection
|
|
// used by the Go standard library.
|
|
package cpu
|
|
|
|
// DebugOptions is set to true by the runtime if the OS supports reading
|
|
// GODEBUG early in runtime startup.
|
|
// This should not be changed after it is initialized.
|
|
var DebugOptions bool
|
|
|
|
// CacheLinePad is used to pad structs to avoid false sharing.
|
|
type CacheLinePad struct{ _ [CacheLinePadSize]byte }
|
|
|
|
// CacheLineSize is the CPU's assumed cache line size.
|
|
// There is currently no runtime detection of the real cache line size
|
|
// so we use the constant per GOARCH CacheLinePadSize as an approximation.
|
|
var CacheLineSize uintptr = CacheLinePadSize
|
|
|
|
// The booleans in X86 contain the correspondingly named cpuid feature bit.
|
|
// HasAVX and HasAVX2 are only set if the OS does support XMM and YMM registers
|
|
// in addition to the cpuid feature bit being set.
|
|
// The struct is padded to avoid false sharing.
|
|
var X86 struct {
|
|
_ CacheLinePad
|
|
HasAES bool
|
|
HasADX bool
|
|
HasAVX bool
|
|
HasAVX2 bool
|
|
HasBMI1 bool
|
|
HasBMI2 bool
|
|
HasERMS bool
|
|
HasFMA bool
|
|
HasOSXSAVE bool
|
|
HasPCLMULQDQ bool
|
|
HasPOPCNT bool
|
|
HasRDTSCP bool
|
|
HasSSE3 bool
|
|
HasSSSE3 bool
|
|
HasSSE41 bool
|
|
HasSSE42 bool
|
|
_ CacheLinePad
|
|
}
|
|
|
|
// The booleans in ARM contain the correspondingly named cpu feature bit.
|
|
// The struct is padded to avoid false sharing.
|
|
var ARM struct {
|
|
_ CacheLinePad
|
|
HasVFPv4 bool
|
|
HasIDIVA bool
|
|
_ CacheLinePad
|
|
}
|
|
|
|
// The booleans in ARM64 contain the correspondingly named cpu feature bit.
|
|
// The struct is padded to avoid false sharing.
|
|
var ARM64 struct {
|
|
_ CacheLinePad
|
|
HasAES bool
|
|
HasPMULL bool
|
|
HasSHA1 bool
|
|
HasSHA2 bool
|
|
HasCRC32 bool
|
|
HasATOMICS bool
|
|
HasCPUID bool
|
|
IsNeoverseN1 bool
|
|
IsZeus bool
|
|
_ CacheLinePad
|
|
}
|
|
|
|
var MIPS64X struct {
|
|
_ CacheLinePad
|
|
HasMSA bool // MIPS SIMD architecture
|
|
_ CacheLinePad
|
|
}
|
|
|
|
// For ppc64(le), it is safe to check only for ISA level starting on ISA v3.00,
|
|
// since there are no optional categories. There are some exceptions that also
|
|
// require kernel support to work (darn, scv), so there are feature bits for
|
|
// those as well. The minimum processor requirement is POWER8 (ISA 2.07).
|
|
// The struct is padded to avoid false sharing.
|
|
var PPC64 struct {
|
|
_ CacheLinePad
|
|
HasDARN bool // Hardware random number generator (requires kernel enablement)
|
|
HasSCV bool // Syscall vectored (requires kernel enablement)
|
|
IsPOWER8 bool // ISA v2.07 (POWER8)
|
|
IsPOWER9 bool // ISA v3.00 (POWER9)
|
|
_ CacheLinePad
|
|
}
|
|
|
|
var S390X struct {
|
|
_ CacheLinePad
|
|
HasZARCH bool // z architecture mode is active [mandatory]
|
|
HasSTFLE bool // store facility list extended [mandatory]
|
|
HasLDISP bool // long (20-bit) displacements [mandatory]
|
|
HasEIMM bool // 32-bit immediates [mandatory]
|
|
HasDFP bool // decimal floating point
|
|
HasETF3EH bool // ETF-3 enhanced
|
|
HasMSA bool // message security assist (CPACF)
|
|
HasAES bool // KM-AES{128,192,256} functions
|
|
HasAESCBC bool // KMC-AES{128,192,256} functions
|
|
HasAESCTR bool // KMCTR-AES{128,192,256} functions
|
|
HasAESGCM bool // KMA-GCM-AES{128,192,256} functions
|
|
HasGHASH bool // KIMD-GHASH function
|
|
HasSHA1 bool // K{I,L}MD-SHA-1 functions
|
|
HasSHA256 bool // K{I,L}MD-SHA-256 functions
|
|
HasSHA512 bool // K{I,L}MD-SHA-512 functions
|
|
HasSHA3 bool // K{I,L}MD-SHA3-{224,256,384,512} and K{I,L}MD-SHAKE-{128,256} functions
|
|
HasVX bool // vector facility. Note: the runtime sets this when it processes auxv records.
|
|
HasVXE bool // vector-enhancements facility 1
|
|
HasKDSA bool // elliptic curve functions
|
|
HasECDSA bool // NIST curves
|
|
HasEDDSA bool // Edwards curves
|
|
_ CacheLinePad
|
|
}
|
|
|
|
// Initialize examines the processor and sets the relevant variables above.
|
|
// This is called by the runtime package early in program initialization,
|
|
// before normal init functions are run. env is set by runtime if the OS supports
|
|
// cpu feature options in GODEBUG.
|
|
func Initialize(env string) {
|
|
doinit()
|
|
processOptions(env)
|
|
}
|
|
|
|
// options contains the cpu debug options that can be used in GODEBUG.
|
|
// Options are arch dependent and are added by the arch specific doinit functions.
|
|
// Features that are mandatory for the specific GOARCH should not be added to options
|
|
// (e.g. SSE2 on amd64).
|
|
var options []option
|
|
|
|
// Option names should be lower case. e.g. avx instead of AVX.
|
|
type option struct {
|
|
Name string
|
|
Feature *bool
|
|
Specified bool // whether feature value was specified in GODEBUG
|
|
Enable bool // whether feature should be enabled
|
|
}
|
|
|
|
// processOptions enables or disables CPU feature values based on the parsed env string.
|
|
// The env string is expected to be of the form cpu.feature1=value1,cpu.feature2=value2...
|
|
// where feature names is one of the architecture specific list stored in the
|
|
// cpu packages options variable and values are either 'on' or 'off'.
|
|
// If env contains cpu.all=off then all cpu features referenced through the options
|
|
// variable are disabled. Other feature names and values result in warning messages.
|
|
func processOptions(env string) {
|
|
field:
|
|
for env != "" {
|
|
field := ""
|
|
i := indexByte(env, ',')
|
|
if i < 0 {
|
|
field, env = env, ""
|
|
} else {
|
|
field, env = env[:i], env[i+1:]
|
|
}
|
|
if len(field) < 4 || field[:4] != "cpu." {
|
|
continue
|
|
}
|
|
i = indexByte(field, '=')
|
|
if i < 0 {
|
|
print("GODEBUG: no value specified for \"", field, "\"\n")
|
|
continue
|
|
}
|
|
key, value := field[4:i], field[i+1:] // e.g. "SSE2", "on"
|
|
|
|
var enable bool
|
|
switch value {
|
|
case "on":
|
|
enable = true
|
|
case "off":
|
|
enable = false
|
|
default:
|
|
print("GODEBUG: value \"", value, "\" not supported for cpu option \"", key, "\"\n")
|
|
continue field
|
|
}
|
|
|
|
if key == "all" {
|
|
for i := range options {
|
|
options[i].Specified = true
|
|
options[i].Enable = enable
|
|
}
|
|
continue field
|
|
}
|
|
|
|
for i := range options {
|
|
if options[i].Name == key {
|
|
options[i].Specified = true
|
|
options[i].Enable = enable
|
|
continue field
|
|
}
|
|
}
|
|
|
|
print("GODEBUG: unknown cpu feature \"", key, "\"\n")
|
|
}
|
|
|
|
for _, o := range options {
|
|
if !o.Specified {
|
|
continue
|
|
}
|
|
|
|
if o.Enable && !*o.Feature {
|
|
print("GODEBUG: can not enable \"", o.Name, "\", missing CPU support\n")
|
|
continue
|
|
}
|
|
|
|
*o.Feature = o.Enable
|
|
}
|
|
}
|
|
|
|
// indexByte returns the index of the first instance of c in s,
|
|
// or -1 if c is not present in s.
|
|
func indexByte(s string, c byte) int {
|
|
for i := 0; i < len(s); i++ {
|
|
if s[i] == c {
|
|
return i
|
|
}
|
|
}
|
|
return -1
|
|
}
|