pax_global_header00006660000000000000000000000064143451151750014520gustar00rootroot0000000000000052 comment=7587a738ad7da237dd30a5a9bd3ffbc2a07a1fdc cpu-0.1.0/000077500000000000000000000000001434511517500123055ustar00rootroot00000000000000cpu-0.1.0/.gitignore000066400000000000000000000003071434511517500142750ustar00rootroot00000000000000# Binaries for programs and plugins *.exe *.exe~ *.dll *.so *.dylib # Test binary, build with `go test -c` *.test # Output of the go coverage tool, specifically when used with LiteIDE *.out .idea/ cpu-0.1.0/LICENSE000066400000000000000000000030651434511517500133160ustar00rootroot00000000000000BSD 3-Clause License Copyright (c) 2018 Temple3x (temple3x@gmail.com) Copyright 2017 The Go Authors Copyright (c) 2015 Klaus Post All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. cpu-0.1.0/README.md000066400000000000000000000005011434511517500135600ustar00rootroot00000000000000# cpu internal/cpu(in Go standard lib) with these detections: >- AVX512 > >- Cache Size > >- Invariant TSC > It also provides: >- False sharing range, see `X86FalseSharingRange` for X86 platform. > >- TSC frequency > >- Name > >- Family & Model # Acknowledgement [klauspost/cpuid](https://github.com/klauspost/cpuid)cpu-0.1.0/cpu.go000066400000000000000000000161041434511517500134250ustar00rootroot00000000000000// 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 go was compiled with GOEXPERIMENT=debugcpu // and GOOS is Linux or Darwin. This variable is linknamed in runtime/proc.go. var debugOptions bool var X86 x86 // "Loads data or instructions from memory to the second-level cache. // To use the streamer, organize the data or instructions in blocks of 128 bytes, // aligned on 128 bytes." // From , // in section 3.7.3 "Hardware Prefetching for Second-Level Cache" // // In practice, I have found use 128bytes can gain better performance than 64bytes (one cache line). const X86FalseSharingRange = 128 // 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. type x86 struct { _ [X86FalseSharingRange]byte HasCMPXCHG16B bool HasAES bool HasADX bool HasAVX bool HasAVX2 bool HasAVX512F bool HasAVX512DQ bool HasAVX512BW bool HasAVX512VL bool HasBMI1 bool HasBMI2 bool HasERMS bool HasFMA bool HasOSXSAVE bool HasPCLMULQDQ bool HasPOPCNT bool HasSSE2 bool HasSSE3 bool HasSSSE3 bool HasSSE41 bool HasSSE42 bool // The invariant TSC will run at a constant rate in all ACPI P-, C-, and T-states. // This is the architectural behavior moving forward. On processors with // invariant TSC support, the OS may use the TSC for wall clock timer services (instead of ACPI or HPET timers). HasInvariantTSC bool Cache Cache // TSCFrequency only meaningful when HasInvariantTSC == true. // Unit: Hz. // // Warn: // 1. If it's 0, means failed to get it from frequency table provided by Intel manual. TSCFrequency uint64 Name string Signature string // DisplayFamily_DisplayModel. Family uint32 // CPU family number. Model uint32 // CPU model number. SteppingID uint32 _ [X86FalseSharingRange]byte } // CPU Cache Size. // -1 if undetected. type Cache struct { L1I int L1D int L2 int L3 int } var PPC64 ppc64 // For ppc64x, 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), so we // maintain some of the old feature checks for optional categories for // safety. // The struct is padded to avoid false sharing. type ppc64 struct { _ [CacheLineSize]byte HasVMX bool // Vector unit (Altivec) HasDFP bool // Decimal Floating Point unit HasVSX bool // Vector-scalar unit HasHTM bool // Hardware Transactional Memory HasISEL bool // Integer select HasVCRYPTO bool // Vector cryptography HasHTMNOSC bool // HTM: kernel-aborted transaction in syscalls 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) _ [CacheLineSize]byte } var ARM64 arm64 // The booleans in arm64 contain the correspondingly named cpu feature bit. // The struct is padded to avoid false sharing. type arm64 struct { _ [CacheLineSize]byte HasFP bool HasASIMD bool HasEVTSTRM bool HasAES bool HasPMULL bool HasSHA1 bool HasSHA2 bool HasCRC32 bool HasATOMICS bool HasFPHP bool HasASIMDHP bool HasCPUID bool HasASIMDRDM bool HasJSCVT bool HasFCMA bool HasLRCPC bool HasDCPOP bool HasSHA3 bool HasSM3 bool HasSM4 bool HasASIMDDP bool HasSHA512 bool HasSVE bool HasASIMDFHM bool _ [CacheLineSize]byte } var S390X s390x type s390x struct { _ [CacheLineSize]byte 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 HasETF3Enhanced 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 HasVX bool // vector facility. Note: the runtime sets this when it processes auxv records. _ [CacheLineSize]byte } // 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 on Linux and Darwin // if go was compiled with GOEXPERIMENT=debugcpu. func init() { doinit() processOptions("") } // options contains the cpu debug options that can be used in GODEBUGCPU. // 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 } // processOptions disables CPU feature values based on the parsed env string. // The env string is expected to be of the form feature1=0,feature2=0... // where feature names is one of the architecture specifc list stored in the // cpu packages options variable. If env contains all=0 then all capabilities // referenced through the options variable are disabled. Other feature // names and values other than 0 are silently ignored. 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:] } i = indexByte(field, '=') if i < 0 { continue } key, value := field[:i], field[i+1:] // Only allow turning off CPU features by specifying '0'. if value == "0" { if key == "all" { for _, v := range options { *v.Feature = false } return } else { for _, v := range options { if v.Name == key { *v.Feature = false continue field } } } } } } // 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 } cpu-0.1.0/cpu_386.go000066400000000000000000000003021434511517500140160ustar00rootroot00000000000000// Copyright 2018 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 const GOARCH = "386" cpu-0.1.0/cpu_amd64.go000066400000000000000000000003041434511517500144130ustar00rootroot00000000000000// Copyright 2018 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 const GOARCH = "amd64" cpu-0.1.0/cpu_amd64p32.go000066400000000000000000000003071434511517500147430ustar00rootroot00000000000000// Copyright 2018 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 const GOARCH = "amd64p32" cpu-0.1.0/cpu_arm.go000066400000000000000000000003061434511517500142610ustar00rootroot00000000000000// 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 const CacheLineSize = 32 cpu-0.1.0/cpu_arm64.go000066400000000000000000000060201434511517500144320ustar00rootroot00000000000000// 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 const CacheLineSize = 64 // arm64 doesn't have a 'cpuid' equivalent, so we rely on HWCAP/HWCAP2. // These are linknamed in runtime/os_linux_arm64.go and are initialized by // archauxv(). var hwcap uint var hwcap2 uint // HWCAP/HWCAP2 bits. These are exposed by Linux. const ( hwcap_FP = (1 << 0) hwcap_ASIMD = (1 << 1) hwcap_EVTSTRM = (1 << 2) hwcap_AES = (1 << 3) hwcap_PMULL = (1 << 4) hwcap_SHA1 = (1 << 5) hwcap_SHA2 = (1 << 6) hwcap_CRC32 = (1 << 7) hwcap_ATOMICS = (1 << 8) hwcap_FPHP = (1 << 9) hwcap_ASIMDHP = (1 << 10) hwcap_CPUID = (1 << 11) hwcap_ASIMDRDM = (1 << 12) hwcap_JSCVT = (1 << 13) hwcap_FCMA = (1 << 14) hwcap_LRCPC = (1 << 15) hwcap_DCPOP = (1 << 16) hwcap_SHA3 = (1 << 17) hwcap_SM3 = (1 << 18) hwcap_SM4 = (1 << 19) hwcap_ASIMDDP = (1 << 20) hwcap_SHA512 = (1 << 21) hwcap_SVE = (1 << 22) hwcap_ASIMDFHM = (1 << 23) ) func doinit() { options = []option{ {"evtstrm", &ARM64.HasEVTSTRM}, {"aes", &ARM64.HasAES}, {"pmull", &ARM64.HasPMULL}, {"sha1", &ARM64.HasSHA1}, {"sha2", &ARM64.HasSHA2}, {"crc32", &ARM64.HasCRC32}, {"atomics", &ARM64.HasATOMICS}, {"fphp", &ARM64.HasFPHP}, {"asimdhp", &ARM64.HasASIMDHP}, {"cpuid", &ARM64.HasCPUID}, {"asimdrdm", &ARM64.HasASIMDRDM}, {"jscvt", &ARM64.HasJSCVT}, {"fcma", &ARM64.HasFCMA}, {"lrcpc", &ARM64.HasLRCPC}, {"dcpop", &ARM64.HasDCPOP}, {"sha3", &ARM64.HasSHA3}, {"sm3", &ARM64.HasSM3}, {"sm4", &ARM64.HasSM4}, {"asimddp", &ARM64.HasASIMDDP}, {"sha512", &ARM64.HasSHA512}, {"sve", &ARM64.HasSVE}, {"asimdfhm", &ARM64.HasASIMDFHM}, // These capabilities should always be enabled on arm64: // {"fp", &ARM64.HasFP}, // {"asimd", &ARM64.HasASIMD}, } // HWCAP feature bits ARM64.HasFP = isSet(hwcap, hwcap_FP) ARM64.HasASIMD = isSet(hwcap, hwcap_ASIMD) ARM64.HasEVTSTRM = isSet(hwcap, hwcap_EVTSTRM) ARM64.HasAES = isSet(hwcap, hwcap_AES) ARM64.HasPMULL = isSet(hwcap, hwcap_PMULL) ARM64.HasSHA1 = isSet(hwcap, hwcap_SHA1) ARM64.HasSHA2 = isSet(hwcap, hwcap_SHA2) ARM64.HasCRC32 = isSet(hwcap, hwcap_CRC32) ARM64.HasATOMICS = isSet(hwcap, hwcap_ATOMICS) ARM64.HasFPHP = isSet(hwcap, hwcap_FPHP) ARM64.HasASIMDHP = isSet(hwcap, hwcap_ASIMDHP) ARM64.HasCPUID = isSet(hwcap, hwcap_CPUID) ARM64.HasASIMDRDM = isSet(hwcap, hwcap_ASIMDRDM) ARM64.HasJSCVT = isSet(hwcap, hwcap_JSCVT) ARM64.HasFCMA = isSet(hwcap, hwcap_FCMA) ARM64.HasLRCPC = isSet(hwcap, hwcap_LRCPC) ARM64.HasDCPOP = isSet(hwcap, hwcap_DCPOP) ARM64.HasSHA3 = isSet(hwcap, hwcap_SHA3) ARM64.HasSM3 = isSet(hwcap, hwcap_SM3) ARM64.HasSM4 = isSet(hwcap, hwcap_SM4) ARM64.HasASIMDDP = isSet(hwcap, hwcap_ASIMDDP) ARM64.HasSHA512 = isSet(hwcap, hwcap_SHA512) ARM64.HasSVE = isSet(hwcap, hwcap_SVE) ARM64.HasASIMDFHM = isSet(hwcap, hwcap_ASIMDFHM) } func isSet(hwc uint, value uint) bool { return hwc&value != 0 } cpu-0.1.0/cpu_mips.go000066400000000000000000000003061434511517500144520ustar00rootroot00000000000000// 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 const CacheLineSize = 32 cpu-0.1.0/cpu_mips64.go000066400000000000000000000003061434511517500146240ustar00rootroot00000000000000// 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 const CacheLineSize = 32 cpu-0.1.0/cpu_mips64le.go000066400000000000000000000003061434511517500151450ustar00rootroot00000000000000// 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 const CacheLineSize = 32 cpu-0.1.0/cpu_mipsle.go000066400000000000000000000003061434511517500147730ustar00rootroot00000000000000// 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 const CacheLineSize = 32 cpu-0.1.0/cpu_no_init.go000066400000000000000000000005151434511517500151430ustar00rootroot00000000000000// Copyright 2018 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. // +build !386 // +build !amd64 // +build !amd64p32 // +build !arm64 // +build !ppc64 // +build !ppc64le // +build !riscv64 // +build !s390x package cpu func doinit() { } cpu-0.1.0/cpu_ppc64x.go000066400000000000000000000040461434511517500146330ustar00rootroot00000000000000// 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. // +build ppc64 ppc64le package cpu const CacheLineSize = 128 // ppc64x doesn't have a 'cpuid' equivalent, so we rely on HWCAP/HWCAP2. // These are linknamed in runtime/os_linux_ppc64x.go and are initialized by // archauxv(). var hwcap uint var hwcap2 uint // HWCAP/HWCAP2 bits. These are exposed by the kernel. const ( // ISA Level _PPC_FEATURE2_ARCH_2_07 = 0x80000000 _PPC_FEATURE2_ARCH_3_00 = 0x00800000 // CPU features _PPC_FEATURE_HAS_ALTIVEC = 0x10000000 _PPC_FEATURE_HAS_DFP = 0x00000400 _PPC_FEATURE_HAS_VSX = 0x00000080 _PPC_FEATURE2_HAS_HTM = 0x40000000 _PPC_FEATURE2_HAS_ISEL = 0x08000000 _PPC_FEATURE2_HAS_VEC_CRYPTO = 0x02000000 _PPC_FEATURE2_HTM_NOSC = 0x01000000 _PPC_FEATURE2_DARN = 0x00200000 _PPC_FEATURE2_SCV = 0x00100000 ) func doinit() { options = []option{ {"htm", &PPC64.HasHTM}, {"htmnosc", &PPC64.HasHTMNOSC}, {"darn", &PPC64.HasDARN}, {"scv", &PPC64.HasSCV}, // These capabilities should always be enabled on ppc64 and ppc64le: // {"vmx", &PPC64.HasVMX}, // {"dfp", &PPC64.HasDFP}, // {"vsx", &PPC64.HasVSX}, // {"isel", &PPC64.HasISEL}, // {"vcrypto", &PPC64.HasVCRYPTO}, } // HWCAP feature bits PPC64.HasVMX = isSet(hwcap, _PPC_FEATURE_HAS_ALTIVEC) PPC64.HasDFP = isSet(hwcap, _PPC_FEATURE_HAS_DFP) PPC64.HasVSX = isSet(hwcap, _PPC_FEATURE_HAS_VSX) // HWCAP2 feature bits PPC64.IsPOWER8 = isSet(hwcap2, _PPC_FEATURE2_ARCH_2_07) PPC64.HasHTM = isSet(hwcap2, _PPC_FEATURE2_HAS_HTM) PPC64.HasISEL = isSet(hwcap2, _PPC_FEATURE2_HAS_ISEL) PPC64.HasVCRYPTO = isSet(hwcap2, _PPC_FEATURE2_HAS_VEC_CRYPTO) PPC64.HasHTMNOSC = isSet(hwcap2, _PPC_FEATURE2_HTM_NOSC) PPC64.IsPOWER9 = isSet(hwcap2, _PPC_FEATURE2_ARCH_3_00) PPC64.HasDARN = isSet(hwcap2, _PPC_FEATURE2_DARN) PPC64.HasSCV = isSet(hwcap2, _PPC_FEATURE2_SCV) } func isSet(hwc uint, value uint) bool { return hwc&value != 0 } cpu-0.1.0/cpu_riscv64.go000066400000000000000000000003311434511517500150000ustar00rootroot00000000000000// Copyright 2019 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 const CacheLineSize = 32 func doinit() { } cpu-0.1.0/cpu_s390x.go000066400000000000000000000101131434511517500143650ustar00rootroot00000000000000// 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 const CacheLineSize = 256 // bitIsSet reports whether the bit at index is set. The bit index // is in big endian order, so bit index 0 is the leftmost bit. func bitIsSet(bits []uint64, index uint) bool { return bits[index/64]&((1<<63)>>(index%64)) != 0 } // function is the function code for the named function. type function uint8 const ( // KM{,A,C,CTR} function codes aes128 function = 18 // AES-128 aes192 = 19 // AES-192 aes256 = 20 // AES-256 // K{I,L}MD function codes sha1 = 1 // SHA-1 sha256 = 2 // SHA-256 sha512 = 3 // SHA-512 // KLMD function codes ghash = 65 // GHASH ) // queryResult contains the result of a Query function // call. Bits are numbered in big endian order so the // leftmost bit (the MSB) is at index 0. type queryResult struct { bits [2]uint64 } // Has reports whether the given functions are present. func (q *queryResult) Has(fns ...function) bool { if len(fns) == 0 { panic("no function codes provided") } for _, f := range fns { if !bitIsSet(q.bits[:], uint(f)) { return false } } return true } // facility is a bit index for the named facility. type facility uint8 const ( // mandatory facilities zarch facility = 1 // z architecture mode is active stflef = 7 // store-facility-list-extended ldisp = 18 // long-displacement eimm = 21 // extended-immediate // miscellaneous facilities dfp = 42 // decimal-floating-point etf3eh = 30 // extended-translation 3 enhancement // cryptography facilities msa = 17 // message-security-assist msa3 = 76 // message-security-assist extension 3 msa4 = 77 // message-security-assist extension 4 msa5 = 57 // message-security-assist extension 5 msa8 = 146 // message-security-assist extension 8 // Note: vx and highgprs are excluded because they require // kernel support and so must be fetched from HWCAP. ) // facilityList contains the result of an STFLE call. // Bits are numbered in big endian order so the // leftmost bit (the MSB) is at index 0. type facilityList struct { bits [4]uint64 } // Has reports whether the given facilities are present. func (s *facilityList) Has(fs ...facility) bool { if len(fs) == 0 { panic("no facility bits provided") } for _, f := range fs { if !bitIsSet(s.bits[:], uint(f)) { return false } } return true } // The following feature detection functions are defined in cpu_s390x.s. // They are likely to be expensive to call so the results should be cached. func stfle() facilityList func kmQuery() queryResult func kmcQuery() queryResult func kmctrQuery() queryResult func kmaQuery() queryResult func kimdQuery() queryResult func klmdQuery() queryResult func doinit() { options = []option{ {"zarch", &S390X.HasZArch}, {"stfle", &S390X.HasSTFLE}, {"ldisp", &S390X.HasLDisp}, {"msa", &S390X.HasMSA}, {"eimm", &S390X.HasEImm}, {"dfp", &S390X.HasDFP}, {"etf3eh", &S390X.HasETF3Enhanced}, {"vx", &S390X.HasVX}, } aes := []function{aes128, aes192, aes256} facilities := stfle() S390X.HasZArch = facilities.Has(zarch) S390X.HasSTFLE = facilities.Has(stflef) S390X.HasLDisp = facilities.Has(ldisp) S390X.HasEImm = facilities.Has(eimm) S390X.HasDFP = facilities.Has(dfp) S390X.HasETF3Enhanced = facilities.Has(etf3eh) S390X.HasMSA = facilities.Has(msa) if S390X.HasMSA { // cipher message km, kmc := kmQuery(), kmcQuery() S390X.HasAES = km.Has(aes...) S390X.HasAESCBC = kmc.Has(aes...) if facilities.Has(msa4) { kmctr := kmctrQuery() S390X.HasAESCTR = kmctr.Has(aes...) } if facilities.Has(msa8) { kma := kmaQuery() S390X.HasAESGCM = kma.Has(aes...) } // compute message digest kimd := kimdQuery() // intermediate (no padding) klmd := klmdQuery() // last (padding) S390X.HasSHA1 = kimd.Has(sha1) && klmd.Has(sha1) S390X.HasSHA256 = kimd.Has(sha256) && klmd.Has(sha256) S390X.HasSHA512 = kimd.Has(sha512) && klmd.Has(sha512) S390X.HasGHASH = kimd.Has(ghash) // KLMD-GHASH does not exist } } cpu-0.1.0/cpu_s390x.s000066400000000000000000000035531434511517500142340ustar00rootroot00000000000000// Copyright 2018 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. // func stfle() facilityList TEXT ·stfle(SB), 4|512, $0-32 MOVD $ret+0(FP), R1 MOVD $3, R0 // last doubleword index to store XC $32, (R1), (R1) // clear 4 doublewords (32 bytes) WORD $0xb2b01000 // store facility list extended (STFLE) RET // func kmQuery() queryResult TEXT ·kmQuery(SB), 4|512, $0-16 MOVD $0, R0 // set function code to 0 (KM-Query) MOVD $ret+0(FP), R1 // address of 16-byte return value WORD $0xB92E0024 // cipher message (KM) RET // func kmcQuery() queryResult TEXT ·kmcQuery(SB), 4|512, $0-16 MOVD $0, R0 // set function code to 0 (KMC-Query) MOVD $ret+0(FP), R1 // address of 16-byte return value WORD $0xB92F0024 // cipher message with chaining (KMC) RET // func kmctrQuery() queryResult TEXT ·kmctrQuery(SB), 4|512, $0-16 MOVD $0, R0 // set function code to 0 (KMCTR-Query) MOVD $ret+0(FP), R1 // address of 16-byte return value WORD $0xB92D4024 // cipher message with counter (KMCTR) RET // func kmaQuery() queryResult TEXT ·kmaQuery(SB), 4|512, $0-16 MOVD $0, R0 // set function code to 0 (KMA-Query) MOVD $ret+0(FP), R1 // address of 16-byte return value WORD $0xb9296024 // cipher message with authentication (KMA) RET // func kimdQuery() queryResult TEXT ·kimdQuery(SB), 4|512, $0-16 MOVD $0, R0 // set function code to 0 (KIMD-Query) MOVD $ret+0(FP), R1 // address of 16-byte return value WORD $0xB93E0024 // compute intermediate message digest (KIMD) RET // func klmdQuery() queryResult TEXT ·klmdQuery(SB), 4|512, $0-16 MOVD $0, R0 // set function code to 0 (KLMD-Query) MOVD $ret+0(FP), R1 // address of 16-byte return value WORD $0xB93F0024 // compute last message digest (KLMD) RET cpu-0.1.0/cpu_wasm.go000066400000000000000000000003061434511517500144510ustar00rootroot00000000000000// Copyright 2018 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 const CacheLineSize = 64 cpu-0.1.0/cpu_x86.go000066400000000000000000000263241434511517500141370ustar00rootroot00000000000000// 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. // +build 386 amd64 amd64p32 package cpu import ( "fmt" "strings" ) const CacheLineSize = 64 // cpuid is implemented in cpu_x86.s. func cpuid(eaxArg, ecxArg uint32) (eax, ebx, ecx, edx uint32) // xgetbv with ecx = 0 is implemented in cpu_x86.s. func xgetbv() (eax, edx uint32) const ( // edx bits cpuid_SSE2 = 1 << 26 // ecx bits cpuid_SSE3 = 1 << 0 cpuid_PCLMULQDQ = 1 << 1 cpuid_SSSE3 = 1 << 9 cpuid_FMA = 1 << 12 cpuid_SSE41 = 1 << 19 cpuid_SSE42 = 1 << 20 cpuid_POPCNT = 1 << 23 cpuid_AES = 1 << 25 cpuid_OSXSAVE = 1 << 27 cpuid_AVX = 1 << 28 cpuid_CMPXCHG16B = 1 << 13 // ebx bits cpuid_BMI1 = 1 << 3 cpuid_AVX2 = 1 << 5 cpuid_BMI2 = 1 << 8 cpuid_ERMS = 1 << 9 cpuid_ADX = 1 << 19 cpuid_AVX512F = 1 << 16 cpuid_AVX512DQ = 1 << 17 cpuid_AVX512BW = 1 << 30 cpuid_AVX512VL = 1 << 31 // edx bits cpuid_Invariant_TSC = 1 << 8 ) func doinit() { options = []option{ {"adx", &X86.HasADX}, {"aes", &X86.HasAES}, {"avx", &X86.HasAVX}, {"avx2", &X86.HasAVX2}, {"bmi1", &X86.HasBMI1}, {"bmi2", &X86.HasBMI2}, {"erms", &X86.HasERMS}, {"fma", &X86.HasFMA}, {"pclmulqdq", &X86.HasPCLMULQDQ}, {"popcnt", &X86.HasPOPCNT}, {"sse3", &X86.HasSSE3}, {"sse41", &X86.HasSSE41}, {"sse42", &X86.HasSSE42}, {"ssse3", &X86.HasSSSE3}, {"avx512f", &X86.HasAVX512F}, {"avx512dq", &X86.HasAVX512DQ}, {"avx512bw", &X86.HasAVX512BW}, {"avx512vl", &X86.HasAVX512VL}, {"invariant_tsc", &X86.HasInvariantTSC}, // sse2 set as last element so it can easily be removed again. See code below. {"sse2", &X86.HasSSE2}, } // Remove sse2 from options on amd64(p32) because SSE2 is a mandatory feature for these GOARCHs. if GOARCH == "amd64" || GOARCH == "amd64p32" { options = options[:len(options)-1] } maxID, _, _, _ := cpuid(0, 0) if maxID < 1 { return } _, _, ecx1, edx1 := cpuid(1, 0) X86.HasSSE2 = isSet(edx1, cpuid_SSE2) X86.HasSSE3 = isSet(ecx1, cpuid_SSE3) X86.HasPCLMULQDQ = isSet(ecx1, cpuid_PCLMULQDQ) X86.HasSSSE3 = isSet(ecx1, cpuid_SSSE3) X86.HasFMA = isSet(ecx1, cpuid_FMA) X86.HasSSE41 = isSet(ecx1, cpuid_SSE41) X86.HasSSE42 = isSet(ecx1, cpuid_SSE42) X86.HasPOPCNT = isSet(ecx1, cpuid_POPCNT) X86.HasAES = isSet(ecx1, cpuid_AES) X86.HasCMPXCHG16B = isSet(ecx1, cpuid_CMPXCHG16B) X86.HasOSXSAVE = isSet(ecx1, cpuid_OSXSAVE) osSupportsAVX := false osSupportsAVX512 := false // For XGETBV, OSXSAVE bit is required and sufficient. if X86.HasOSXSAVE { eax, _ := xgetbv() // Check if XMM and YMM registers have OS support. osSupportsAVX = isSet(eax, 1<<1) && isSet(eax, 1<<2) // Check is ZMM registers have OS support. osSupportsAVX512 = isSet(eax>>5, 7) && isSet(eax>>1, 3) } X86.HasAVX = isSet(ecx1, cpuid_AVX) && osSupportsAVX if maxID < 7 { return } _, ebx7, _, _ := cpuid(7, 0) X86.HasBMI1 = isSet(ebx7, cpuid_BMI1) X86.HasAVX2 = isSet(ebx7, cpuid_AVX2) && osSupportsAVX X86.HasAVX512F = isSet(ebx7, cpuid_AVX512F) && osSupportsAVX512 X86.HasAVX512DQ = isSet(ebx7, cpuid_AVX512DQ) && osSupportsAVX512 X86.HasAVX512BW = isSet(ebx7, cpuid_AVX512BW) && osSupportsAVX512 X86.HasAVX512VL = isSet(ebx7, cpuid_AVX512VL) && osSupportsAVX512 X86.HasBMI2 = isSet(ebx7, cpuid_BMI2) X86.HasERMS = isSet(ebx7, cpuid_ERMS) X86.HasADX = isSet(ebx7, cpuid_ADX) X86.Cache = getCacheSize() X86.HasInvariantTSC = hasInvariantTSC() X86.Family, X86.Model, X86.SteppingID = getVersionInfo() X86.Signature = makeSignature(X86.Family, X86.Model) X86.Name = getName() X86.TSCFrequency = getNativeTSCFrequency(X86.Name, X86.Signature, X86.SteppingID) } func isSet(hwc uint32, value uint32) bool { return hwc&value != 0 } func hasInvariantTSC() bool { if maxExtendedFunction() < 0x80000007 { return false } _, _, _, edx := cpuid(0x80000007, 0) return isSet(edx, cpuid_Invariant_TSC) } func getName() string { if maxExtendedFunction() >= 0x80000004 { v := make([]uint32, 0, 48) for i := uint32(0); i < 3; i++ { a, b, c, d := cpuid(0x80000002+i, 0) v = append(v, a, b, c, d) } return strings.Trim(string(valAsString(v...)), " ") } return "unknown" } // getNativeTSCFrequency gets TSC frequency from CPUID, // only supports Intel (Skylake or later microarchitecture) & key information is from Intel manual & kernel codes // (especially this commit: https://github.com/torvalds/linux/commit/604dc9170f2435d27da5039a3efd757dceadc684). func getNativeTSCFrequency(name, sign string, steppingID uint32) uint64 { if vendorID() != Intel { return 0 } if maxFunctionID() < 0x15 { return 0 } // ApolloLake, GeminiLake, CannonLake (and presumably all new chipsets // from this point) report the crystal frequency directly via CPUID.0x15. // That's definitive data that we can rely upon. eax, ebx, ecx, _ := cpuid(0x15, 0) // If ebx is 0, the TSC/”core crystal clock” ratio is not enumerated. // We won't provide TSC frequency detection in this situation. if eax == 0 || ebx == 0 { return 0 } // Skylake, Kabylake and all variants of those two chipsets report a // crystal frequency of zero. if ecx == 0 { // Crystal clock frequency is not enumerated. ecx = getCrystalClockFrequency(sign, steppingID) } // TSC frequency = “core crystal clock frequency” * EBX/EAX. return uint64(ecx) * (uint64(ebx) / uint64(eax)) } // Copied from: CPUID Signature values of DisplayFamily and DisplayModel, // in Intel® 64 and IA-32 Architectures Software Developer’s Manual // Volume 4: Model-Specific Registers // & https://github.com/torvalds/linux/blob/master/arch/x86/include/asm/intel-family.h const ( IntelFam6SkylakeL = "06_4EH" IntelFam6Skylake = "06_5EH" IntelFam6XeonScalable = "06_55H" IntelFam6KabylakeL = "06_8EH" IntelFam6Kabylake = "06_9EH" ) // getCrystalClockFrequency gets crystal clock frequency // for Intel processors in which CPUID.15H.EBX[31:0] ÷ CPUID.0x15.EAX[31:0] is enumerated // but CPUID.15H.ECX is not enumerated using this function to get nominal core crystal clock frequency. // // Actually these crystal clock frequencies provided by Intel hardcoded tables are not so accurate in some cases, // e.g. SkyLake server CPU may have issue (All SKX subject the crystal to an EMI reduction circuit that //reduces its actual frequency by (approximately) -0.25%): // see https://lore.kernel.org/lkml/ff6dcea166e8ff8f2f6a03c17beab2cb436aa779.1513920414.git.len.brown@intel.com/ // for more details. // With this report, I set a coefficient (0.9975) for IntelFam6SkyLakeX. // // Unlike the kernel way (mentioned in https://github.com/torvalds/linux/commit/604dc9170f2435d27da5039a3efd757dceadc684), // I prefer the Intel hardcoded tables, (in // 18.7.3 Determining the Processor Base Frequency, Table 18-85. Nominal Core Crystal Clock Frequency) // because after some testing (comparing with wall clock, see https://github.com/templexxx/tsc/tsc_test.go for more details), // I found hardcoded tables are more accurate. func getCrystalClockFrequency(sign string, steppingID uint32) uint32 { if maxFunctionID() < 0x16 { return 0 } switch sign { case IntelFam6SkylakeL: return 24 * 1000 * 1000 case IntelFam6Skylake: return 24 * 1000 * 1000 case IntelFam6XeonScalable: // SKL-SP. // see: https://community.intel.com/t5/Software-Tuning-Performance/How-to-detect-microarchitecture-on-Xeon-Scalable/m-p/1205162#M7633. if steppingID == 0x2 || steppingID == 0x3 || steppingID == 0x4 { return 25 * 1000 * 1000 * 0.9975 } return 25 * 1000 * 1000 // TODO check other Xeon Scalable has no slow down issue. case IntelFam6KabylakeL: return 24 * 1000 * 1000 case IntelFam6Kabylake: return 24 * 1000 * 1000 } return 0 } func getVersionInfo() (uint32, uint32, uint32) { if maxFunctionID() < 0x1 { return 0, 0, 0 } eax, _, _, _ := cpuid(1, 0) family := (eax >> 8) & 0xf displayFamily := family if family == 0xf { displayFamily = ((eax >> 20) & 0xff) + family } model := (eax >> 4) & 0xf displayModel := model if family == 0x6 || family == 0xf { displayModel = ((eax >> 12) & 0xf0) + model } return displayFamily, displayModel, eax & 0x7 } // signature format: XX_XXH func makeSignature(family, model uint32) string { signature := strings.ToUpper(fmt.Sprintf("0%x_0%xH", family, model)) ss := strings.Split(signature, "_") for i, s := range ss { // Maybe insert too more `0`, drop it. if len(s) > 2 { s = s[1:] ss[i] = s } } return strings.Join(ss, "_") } // getCacheSize is from // https://github.com/klauspost/cpuid/blob/5a626f7029c910cc8329dae5405ee4f65034bce5/cpuid.go#L723 func getCacheSize() Cache { c := Cache{ L1I: -1, L1D: -1, L2: -1, L3: -1, } vendor := vendorID() switch vendor { case Intel: if maxFunctionID() < 4 { return c } for i := uint32(0); ; i++ { eax, ebx, ecx, _ := cpuid(4, i) cacheType := eax & 15 if cacheType == 0 { break } cacheLevel := (eax >> 5) & 7 coherency := int(ebx&0xfff) + 1 partitions := int((ebx>>12)&0x3ff) + 1 associativity := int((ebx>>22)&0x3ff) + 1 sets := int(ecx) + 1 size := associativity * partitions * coherency * sets switch cacheLevel { case 1: if cacheType == 1 { // 1 = Data Cache c.L1D = size } else if cacheType == 2 { // 2 = Instruction Cache c.L1I = size } else { if c.L1D < 0 { c.L1I = size } if c.L1I < 0 { c.L1I = size } } case 2: c.L2 = size case 3: c.L3 = size } } case AMD, Hygon: // Untested. if maxExtendedFunction() < 0x80000005 { return c } _, _, ecx, edx := cpuid(0x80000005, 0) c.L1D = int(((ecx >> 24) & 0xFF) * 1024) c.L1I = int(((edx >> 24) & 0xFF) * 1024) if maxExtendedFunction() < 0x80000006 { return c } _, _, ecx, _ = cpuid(0x80000006, 0) c.L2 = int(((ecx >> 16) & 0xFFFF) * 1024) } return c } func maxFunctionID() uint32 { a, _, _, _ := cpuid(0, 0) return a } func maxExtendedFunction() uint32 { eax, _, _, _ := cpuid(0x80000000, 0) return eax } const ( Other = iota Intel AMD VIA Transmeta NSC KVM // Kernel-based Virtual Machine MSVM // Microsoft Hyper-V or Windows Virtual PC VMware XenHVM Bhyve Hygon ) // Except from http://en.wikipedia.org/wiki/CPUID#EAX.3D0:_Get_vendor_ID var vendorMapping = map[string]int{ "AMDisbetter!": AMD, "AuthenticAMD": AMD, "CentaurHauls": VIA, "GenuineIntel": Intel, "TransmetaCPU": Transmeta, "GenuineTMx86": Transmeta, "Geode by NSC": NSC, "VIA VIA VIA ": VIA, "KVMKVMKVMKVM": KVM, "Microsoft Hv": MSVM, "VMwareVMware": VMware, "XenVMMXenVMM": XenHVM, "bhyve bhyve ": Bhyve, "HygonGenuine": Hygon, } func vendorID() int { _, b, c, d := cpuid(0, 0) v := valAsString(b, d, c) vend, ok := vendorMapping[string(v)] if !ok { return Other } return vend } func valAsString(values ...uint32) []byte { r := make([]byte, 4*len(values)) for i, v := range values { dst := r[i*4:] dst[0] = byte(v & 0xff) dst[1] = byte((v >> 8) & 0xff) dst[2] = byte((v >> 16) & 0xff) dst[3] = byte((v >> 24) & 0xff) switch { case dst[0] == 0: return r[:i*4] case dst[1] == 0: return r[:i*4+1] case dst[2] == 0: return r[:i*4+2] case dst[3] == 0: return r[:i*4+3] } } return r } cpu-0.1.0/cpu_x86.s000066400000000000000000000012161434511517500137650ustar00rootroot00000000000000// 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. // +build 386 amd64 amd64p32 // func cpuid(eaxArg, ecxArg uint32) (eax, ebx, ecx, edx uint32) TEXT ·cpuid(SB), 4, $0-24 MOVL eaxArg+0(FP), AX MOVL ecxArg+4(FP), CX CPUID MOVL AX, eax+8(FP) MOVL BX, ebx+12(FP) MOVL CX, ecx+16(FP) MOVL DX, edx+20(FP) RET // func xgetbv() (eax, edx uint32) TEXT ·xgetbv(SB),4,$0-8 #ifdef GOOS_nacl // nacl does not support XGETBV. MOVL $0, eax+0(FP) MOVL $0, edx+4(FP) #else MOVL $0, CX XGETBV MOVL AX, eax+0(FP) MOVL DX, edx+4(FP) #endif RET