catinello.eu/x/cpuid@v0.0.0-20231214173555-81a76c018636/cpuid.go (about)

     1  // Copyright (c) 2015 Klaus Post, released under MIT License. See LICENSE file.
     2  
     3  // Package cpuid provides information about the CPU running the current program.
     4  //
     5  // CPU features are detected on startup, and kept for fast access through the life of the application.
     6  // Currently x86 / x64 (AMD64) as well as arm64 is supported.
     7  //
     8  // You can access the CPU information by accessing the shared CPU variable of the cpuid library.
     9  //
    10  // Package home: https://catinello.eu/x/cpuid
    11  package cpuid
    12  
    13  import (
    14  	"flag"
    15  	"fmt"
    16  	"math"
    17  	"math/bits"
    18  	"os"
    19  	"runtime"
    20  	"strings"
    21  )
    22  
    23  // AMD refererence: https://www.amd.com/system/files/TechDocs/25481.pdf
    24  // and Processor Programming Reference (PPR)
    25  
    26  // Vendor is a representation of a CPU vendor.
    27  type Vendor int
    28  
    29  const (
    30  	VendorUnknown Vendor = iota
    31  	Intel
    32  	AMD
    33  	VIA
    34  	Transmeta
    35  	NSC
    36  	KVM  // Kernel-based Virtual Machine
    37  	MSVM // Microsoft Hyper-V or Windows Virtual PC
    38  	VMware
    39  	XenHVM
    40  	Bhyve
    41  	Hygon
    42  	SiS
    43  	RDC
    44  
    45  	Ampere
    46  	ARM
    47  	Broadcom
    48  	Cavium
    49  	DEC
    50  	Fujitsu
    51  	Infineon
    52  	Motorola
    53  	NVIDIA
    54  	AMCC
    55  	Qualcomm
    56  	Marvell
    57  
    58  	lastVendor
    59  )
    60  
    61  //go:generate stringer -type=FeatureID,Vendor
    62  
    63  // FeatureID is the ID of a specific cpu feature.
    64  type FeatureID int
    65  
    66  const (
    67  	// Keep index -1 as unknown
    68  	UNKNOWN = -1
    69  
    70  	// Add features
    71  	ADX                FeatureID = iota // Intel ADX (Multi-Precision Add-Carry Instruction Extensions)
    72  	AESNI                               // Advanced Encryption Standard New Instructions
    73  	AMD3DNOW                            // AMD 3DNOW
    74  	AMD3DNOWEXT                         // AMD 3DNowExt
    75  	AMXBF16                             // Tile computational operations on BFLOAT16 numbers
    76  	AMXINT8                             // Tile computational operations on 8-bit integers
    77  	AMXTILE                             // Tile architecture
    78  	AVX                                 // AVX functions
    79  	AVX2                                // AVX2 functions
    80  	AVX512BF16                          // AVX-512 BFLOAT16 Instructions
    81  	AVX512BITALG                        // AVX-512 Bit Algorithms
    82  	AVX512BW                            // AVX-512 Byte and Word Instructions
    83  	AVX512CD                            // AVX-512 Conflict Detection Instructions
    84  	AVX512DQ                            // AVX-512 Doubleword and Quadword Instructions
    85  	AVX512ER                            // AVX-512 Exponential and Reciprocal Instructions
    86  	AVX512F                             // AVX-512 Foundation
    87  	AVX512FP16                          // AVX-512 FP16 Instructions
    88  	AVX512IFMA                          // AVX-512 Integer Fused Multiply-Add Instructions
    89  	AVX512PF                            // AVX-512 Prefetch Instructions
    90  	AVX512VBMI                          // AVX-512 Vector Bit Manipulation Instructions
    91  	AVX512VBMI2                         // AVX-512 Vector Bit Manipulation Instructions, Version 2
    92  	AVX512VL                            // AVX-512 Vector Length Extensions
    93  	AVX512VNNI                          // AVX-512 Vector Neural Network Instructions
    94  	AVX512VP2INTERSECT                  // AVX-512 Intersect for D/Q
    95  	AVX512VPOPCNTDQ                     // AVX-512 Vector Population Count Doubleword and Quadword
    96  	AVXSLOW                             // Indicates the CPU performs 2 128 bit operations instead of one
    97  	AVXVNNI                             // AVX (VEX encoded) VNNI neural network instructions
    98  	BMI1                                // Bit Manipulation Instruction Set 1
    99  	BMI2                                // Bit Manipulation Instruction Set 2
   100  	CETIBT                              // Intel CET Indirect Branch Tracking
   101  	CETSS                               // Intel CET Shadow Stack
   102  	CLDEMOTE                            // Cache Line Demote
   103  	CLMUL                               // Carry-less Multiplication
   104  	CLZERO                              // CLZERO instruction supported
   105  	CMOV                                // i686 CMOV
   106  	CMPSB_SCADBS_SHORT                  // Fast short CMPSB and SCASB
   107  	CMPXCHG8                            // CMPXCHG8 instruction
   108  	CPBOOST                             // Core Performance Boost
   109  	CX16                                // CMPXCHG16B Instruction
   110  	ENQCMD                              // Enqueue Command
   111  	ERMS                                // Enhanced REP MOVSB/STOSB
   112  	F16C                                // Half-precision floating-point conversion
   113  	FMA3                                // Intel FMA 3. Does not imply AVX.
   114  	FMA4                                // Bulldozer FMA4 functions
   115  	FXSR                                // FXSAVE, FXRESTOR instructions, CR4 bit 9
   116  	FXSROPT                             // FXSAVE/FXRSTOR optimizations
   117  	GFNI                                // Galois Field New Instructions. May require other features (AVX, AVX512VL,AVX512F) based on usage.
   118  	HLE                                 // Hardware Lock Elision
   119  	HRESET                              // If set CPU supports history reset and the IA32_HRESET_ENABLE MSR
   120  	HTT                                 // Hyperthreading (enabled)
   121  	HWA                                 // Hardware assert supported. Indicates support for MSRC001_10
   122  	HYPERVISOR                          // This bit has been reserved by Intel & AMD for use by hypervisors
   123  	IBPB                                // Indirect Branch Restricted Speculation (IBRS) and Indirect Branch Predictor Barrier (IBPB)
   124  	IBS                                 // Instruction Based Sampling (AMD)
   125  	IBSBRNTRGT                          // Instruction Based Sampling Feature (AMD)
   126  	IBSFETCHSAM                         // Instruction Based Sampling Feature (AMD)
   127  	IBSFFV                              // Instruction Based Sampling Feature (AMD)
   128  	IBSOPCNT                            // Instruction Based Sampling Feature (AMD)
   129  	IBSOPCNTEXT                         // Instruction Based Sampling Feature (AMD)
   130  	IBSOPSAM                            // Instruction Based Sampling Feature (AMD)
   131  	IBSRDWROPCNT                        // Instruction Based Sampling Feature (AMD)
   132  	IBSRIPINVALIDCHK                    // Instruction Based Sampling Feature (AMD)
   133  	IBS_PREVENTHOST                     // Disallowing IBS use by the host supported
   134  	INT_WBINVD                          // WBINVD/WBNOINVD are interruptible.
   135  	INVLPGB                             // NVLPGB and TLBSYNC instruction supported
   136  	LAHF                                // LAHF/SAHF in long mode
   137  	LAM                                 // If set, CPU supports Linear Address Masking
   138  	LBRVIRT                             // LBR virtualization
   139  	LZCNT                               // LZCNT instruction
   140  	MCAOVERFLOW                         // MCA overflow recovery support.
   141  	MCOMMIT                             // MCOMMIT instruction supported
   142  	MMX                                 // standard MMX
   143  	MMXEXT                              // SSE integer functions or AMD MMX ext
   144  	MOVBE                               // MOVBE instruction (big-endian)
   145  	MOVDIR64B                           // Move 64 Bytes as Direct Store
   146  	MOVDIRI                             // Move Doubleword as Direct Store
   147  	MOVSB_ZL                            // Fast Zero-Length MOVSB
   148  	MPX                                 // Intel MPX (Memory Protection Extensions)
   149  	MSRIRC                              // Instruction Retired Counter MSR available
   150  	MSR_PAGEFLUSH                       // Page Flush MSR available
   151  	NRIPS                               // Indicates support for NRIP save on VMEXIT
   152  	NX                                  // NX (No-Execute) bit
   153  	OSXSAVE                             // XSAVE enabled by OS
   154  	PCONFIG                             // PCONFIG for Intel Multi-Key Total Memory Encryption
   155  	POPCNT                              // POPCNT instruction
   156  	RDPRU                               // RDPRU instruction supported
   157  	RDRAND                              // RDRAND instruction is available
   158  	RDSEED                              // RDSEED instruction is available
   159  	RDTSCP                              // RDTSCP Instruction
   160  	RTM                                 // Restricted Transactional Memory
   161  	RTM_ALWAYS_ABORT                    // Indicates that the loaded microcode is forcing RTM abort.
   162  	SERIALIZE                           // Serialize Instruction Execution
   163  	SEV                                 // AMD Secure Encrypted Virtualization supported
   164  	SEV_64BIT                           // AMD SEV guest execution only allowed from a 64-bit host
   165  	SEV_ALTERNATIVE                     // AMD SEV Alternate Injection supported
   166  	SEV_DEBUGSWAP                       // Full debug state swap supported for SEV-ES guests
   167  	SEV_ES                              // AMD SEV Encrypted State supported
   168  	SEV_RESTRICTED                      // AMD SEV Restricted Injection supported
   169  	SEV_SNP                             // AMD SEV Secure Nested Paging supported
   170  	SGX                                 // Software Guard Extensions
   171  	SGXLC                               // Software Guard Extensions Launch Control
   172  	SHA                                 // Intel SHA Extensions
   173  	SME                                 // AMD Secure Memory Encryption supported
   174  	SME_COHERENT                        // AMD Hardware cache coherency across encryption domains enforced
   175  	SSE                                 // SSE functions
   176  	SSE2                                // P4 SSE functions
   177  	SSE3                                // Prescott SSE3 functions
   178  	SSE4                                // Penryn SSE4.1 functions
   179  	SSE42                               // Nehalem SSE4.2 functions
   180  	SSE4A                               // AMD Barcelona microarchitecture SSE4a instructions
   181  	SSSE3                               // Conroe SSSE3 functions
   182  	STIBP                               // Single Thread Indirect Branch Predictors
   183  	STOSB_SHORT                         // Fast short STOSB
   184  	SUCCOR                              // Software uncorrectable error containment and recovery capability.
   185  	SVM                                 // AMD Secure Virtual Machine
   186  	SVMDA                               // Indicates support for the SVM decode assists.
   187  	SVMFBASID                           // SVM, Indicates that TLB flush events, including CR3 writes and CR4.PGE toggles, flush only the current ASID's TLB entries. Also indicates support for the extended VMCBTLB_Control
   188  	SVML                                // AMD SVM lock. Indicates support for SVM-Lock.
   189  	SVMNP                               // AMD SVM nested paging
   190  	SVMPF                               // SVM pause intercept filter. Indicates support for the pause intercept filter
   191  	SVMPFT                              // SVM PAUSE filter threshold. Indicates support for the PAUSE filter cycle count threshold
   192  	SYSCALL                             // System-Call Extension (SCE): SYSCALL and SYSRET instructions.
   193  	SYSEE                               // SYSENTER and SYSEXIT instructions
   194  	TBM                                 // AMD Trailing Bit Manipulation
   195  	TME                                 // Intel Total Memory Encryption. The following MSRs are supported: IA32_TME_CAPABILITY, IA32_TME_ACTIVATE, IA32_TME_EXCLUDE_MASK, and IA32_TME_EXCLUDE_BASE.
   196  	TSCRATEMSR                          // MSR based TSC rate control. Indicates support for MSR TSC ratio MSRC000_0104
   197  	TSXLDTRK                            // Intel TSX Suspend Load Address Tracking
   198  	VAES                                // Vector AES. AVX(512) versions requires additional checks.
   199  	VMCBCLEAN                           // VMCB clean bits. Indicates support for VMCB clean bits.
   200  	VMPL                                // AMD VM Permission Levels supported
   201  	VMSA_REGPROT                        // AMD VMSA Register Protection supported
   202  	VMX                                 // Virtual Machine Extensions
   203  	VPCLMULQDQ                          // Carry-Less Multiplication Quadword. Requires AVX for 3 register versions.
   204  	VTE                                 // AMD Virtual Transparent Encryption supported
   205  	WAITPKG                             // TPAUSE, UMONITOR, UMWAIT
   206  	WBNOINVD                            // Write Back and Do Not Invalidate Cache
   207  	X87                                 // FPU
   208  	XGETBV1                             // Supports XGETBV with ECX = 1
   209  	XOP                                 // Bulldozer XOP functions
   210  	XSAVE                               // XSAVE, XRESTOR, XSETBV, XGETBV
   211  	XSAVEC                              // Supports XSAVEC and the compacted form of XRSTOR.
   212  	XSAVEOPT                            // XSAVEOPT available
   213  	XSAVES                              // Supports XSAVES/XRSTORS and IA32_XSS
   214  
   215  	// ARM features:
   216  	AESARM   // AES instructions
   217  	ARMCPUID // Some CPU ID registers readable at user-level
   218  	ASIMD    // Advanced SIMD
   219  	ASIMDDP  // SIMD Dot Product
   220  	ASIMDHP  // Advanced SIMD half-precision floating point
   221  	ASIMDRDM // Rounding Double Multiply Accumulate/Subtract (SQRDMLAH/SQRDMLSH)
   222  	ATOMICS  // Large System Extensions (LSE)
   223  	CRC32    // CRC32/CRC32C instructions
   224  	DCPOP    // Data cache clean to Point of Persistence (DC CVAP)
   225  	EVTSTRM  // Generic timer
   226  	FCMA     // Floatin point complex number addition and multiplication
   227  	FP       // Single-precision and double-precision floating point
   228  	FPHP     // Half-precision floating point
   229  	GPA      // Generic Pointer Authentication
   230  	JSCVT    // Javascript-style double->int convert (FJCVTZS)
   231  	LRCPC    // Weaker release consistency (LDAPR, etc)
   232  	PMULL    // Polynomial Multiply instructions (PMULL/PMULL2)
   233  	SHA1     // SHA-1 instructions (SHA1C, etc)
   234  	SHA2     // SHA-2 instructions (SHA256H, etc)
   235  	SHA3     // SHA-3 instructions (EOR3, RAXI, XAR, BCAX)
   236  	SHA512   // SHA512 instructions
   237  	SM3      // SM3 instructions
   238  	SM4      // SM4 instructions
   239  	SVE      // Scalable Vector Extension
   240  	// Keep it last. It automatically defines the size of []flagSet
   241  	lastID
   242  
   243  	firstID FeatureID = UNKNOWN + 1
   244  )
   245  
   246  // CPUInfo contains information about the detected system CPU.
   247  type CPUInfo struct {
   248  	BrandName      string  // Brand name reported by the CPU
   249  	VendorID       Vendor  // Comparable CPU vendor ID
   250  	VendorString   string  // Raw vendor string.
   251  	featureSet     flagSet // Features of the CPU
   252  	PhysicalCores  int     // Number of physical processor cores in your CPU. Will be 0 if undetectable.
   253  	ThreadsPerCore int     // Number of threads per physical core. Will be 1 if undetectable.
   254  	LogicalCores   int     // Number of physical cores times threads that can run on each core through the use of hyperthreading. Will be 0 if undetectable.
   255  	Family         int     // CPU family number
   256  	Model          int     // CPU model number
   257  	Stepping       int     // CPU stepping info
   258  	CacheLine      int     // Cache line size in bytes. Will be 0 if undetectable.
   259  	Hz             int64   // Clock speed, if known, 0 otherwise. Will attempt to contain base clock speed.
   260  	BoostFreq      int64   // Max clock speed, if known, 0 otherwise
   261  	Cache          struct {
   262  		L1I int // L1 Instruction Cache (per core or shared). Will be -1 if undetected
   263  		L1D int // L1 Data Cache (per core or shared). Will be -1 if undetected
   264  		L2  int // L2 Cache (per core or shared). Will be -1 if undetected
   265  		L3  int // L3 Cache (per core, per ccx or shared). Will be -1 if undetected
   266  	}
   267  	SGX       SGXSupport
   268  	maxFunc   uint32
   269  	maxExFunc uint32
   270  }
   271  
   272  var cpuid func(op uint32) (eax, ebx, ecx, edx uint32)
   273  var cpuidex func(op, op2 uint32) (eax, ebx, ecx, edx uint32)
   274  var xgetbv func(index uint32) (eax, edx uint32)
   275  var rdtscpAsm func() (eax, ebx, ecx, edx uint32)
   276  var darwinHasAVX512 = func() bool { return false }
   277  
   278  // CPU contains information about the CPU as detected on startup,
   279  // or when Detect last was called.
   280  //
   281  // Use this as the primary entry point to you data.
   282  var CPU CPUInfo
   283  
   284  func init() {
   285  	initCPU()
   286  	Detect()
   287  }
   288  
   289  // Detect will re-detect current CPU info.
   290  // This will replace the content of the exported CPU variable.
   291  //
   292  // Unless you expect the CPU to change while you are running your program
   293  // you should not need to call this function.
   294  // If you call this, you must ensure that no other goroutine is accessing the
   295  // exported CPU variable.
   296  func Detect() {
   297  	// Set defaults
   298  	CPU.ThreadsPerCore = 1
   299  	CPU.Cache.L1I = -1
   300  	CPU.Cache.L1D = -1
   301  	CPU.Cache.L2 = -1
   302  	CPU.Cache.L3 = -1
   303  	safe := true
   304  	if detectArmFlag != nil {
   305  		safe = !*detectArmFlag
   306  	}
   307  	addInfo(&CPU, safe)
   308  	if displayFeats != nil && *displayFeats {
   309  		fmt.Println("cpu features:", strings.Join(CPU.FeatureSet(), ","))
   310  		// Exit with non-zero so tests will print value.
   311  		os.Exit(1)
   312  	}
   313  	if disableFlag != nil {
   314  		s := strings.Split(*disableFlag, ",")
   315  		for _, feat := range s {
   316  			feat := ParseFeature(strings.TrimSpace(feat))
   317  			if feat != UNKNOWN {
   318  				CPU.featureSet.unset(feat)
   319  			}
   320  		}
   321  	}
   322  }
   323  
   324  // DetectARM will detect ARM64 features.
   325  // This is NOT done automatically since it can potentially crash
   326  // if the OS does not handle the command.
   327  // If in the future this can be done safely this function may not
   328  // do anything.
   329  func DetectARM() {
   330  	addInfo(&CPU, false)
   331  }
   332  
   333  var detectArmFlag *bool
   334  var displayFeats *bool
   335  var disableFlag *string
   336  
   337  // Flags will enable flags.
   338  // This must be called *before* flag.Parse AND
   339  // Detect must be called after the flags have been parsed.
   340  // Note that this means that any detection used in init() functions
   341  // will not contain these flags.
   342  func Flags() {
   343  	disableFlag = flag.String("cpu.disable", "", "disable cpu features; comma separated list")
   344  	displayFeats = flag.Bool("cpu.features", false, "lists cpu features and exits")
   345  	detectArmFlag = flag.Bool("cpu.arm", false, "allow ARM features to be detected; can potentially crash")
   346  }
   347  
   348  // Supports returns whether the CPU supports all of the requested features.
   349  func (c CPUInfo) Supports(ids ...FeatureID) bool {
   350  	for _, id := range ids {
   351  		if !c.featureSet.inSet(id) {
   352  			return false
   353  		}
   354  	}
   355  	return true
   356  }
   357  
   358  // Has allows for checking a single feature.
   359  // Should be inlined by the compiler.
   360  func (c CPUInfo) Has(id FeatureID) bool {
   361  	return c.featureSet.inSet(id)
   362  }
   363  
   364  // AnyOf returns whether the CPU supports one or more of the requested features.
   365  func (c CPUInfo) AnyOf(ids ...FeatureID) bool {
   366  	for _, id := range ids {
   367  		if c.featureSet.inSet(id) {
   368  			return true
   369  		}
   370  	}
   371  	return false
   372  }
   373  
   374  // https://en.wikipedia.org/wiki/X86-64#Microarchitecture_levels
   375  var level1Features = flagSetWith(CMOV, CMPXCHG8, X87, FXSR, MMX, SYSCALL, SSE, SSE2)
   376  var level2Features = flagSetWith(CMOV, CMPXCHG8, X87, FXSR, MMX, SYSCALL, SSE, SSE2, CX16, LAHF, POPCNT, SSE3, SSE4, SSE42, SSSE3)
   377  var level3Features = flagSetWith(CMOV, CMPXCHG8, X87, FXSR, MMX, SYSCALL, SSE, SSE2, CX16, LAHF, POPCNT, SSE3, SSE4, SSE42, SSSE3, AVX, AVX2, BMI1, BMI2, F16C, FMA3, LZCNT, MOVBE, OSXSAVE)
   378  var level4Features = flagSetWith(CMOV, CMPXCHG8, X87, FXSR, MMX, SYSCALL, SSE, SSE2, CX16, LAHF, POPCNT, SSE3, SSE4, SSE42, SSSE3, AVX, AVX2, BMI1, BMI2, F16C, FMA3, LZCNT, MOVBE, OSXSAVE, AVX512F, AVX512BW, AVX512CD, AVX512DQ, AVX512VL)
   379  
   380  // X64Level returns the microarchitecture level detected on the CPU.
   381  // If features are lacking or non x64 mode, 0 is returned.
   382  // See https://en.wikipedia.org/wiki/X86-64#Microarchitecture_levels
   383  func (c CPUInfo) X64Level() int {
   384  	if c.featureSet.hasSet(level4Features) {
   385  		return 4
   386  	}
   387  	if c.featureSet.hasSet(level3Features) {
   388  		return 3
   389  	}
   390  	if c.featureSet.hasSet(level2Features) {
   391  		return 2
   392  	}
   393  	if c.featureSet.hasSet(level1Features) {
   394  		return 1
   395  	}
   396  	return 0
   397  }
   398  
   399  // Disable will disable one or several features.
   400  func (c *CPUInfo) Disable(ids ...FeatureID) bool {
   401  	for _, id := range ids {
   402  		c.featureSet.unset(id)
   403  	}
   404  	return true
   405  }
   406  
   407  // Enable will disable one or several features even if they were undetected.
   408  // This is of course not recommended for obvious reasons.
   409  func (c *CPUInfo) Enable(ids ...FeatureID) bool {
   410  	for _, id := range ids {
   411  		c.featureSet.set(id)
   412  	}
   413  	return true
   414  }
   415  
   416  // IsVendor returns true if vendor is recognized as Intel
   417  func (c CPUInfo) IsVendor(v Vendor) bool {
   418  	return c.VendorID == v
   419  }
   420  
   421  // FeatureSet returns all available features as strings.
   422  func (c CPUInfo) FeatureSet() []string {
   423  	s := make([]string, 0, c.featureSet.nEnabled())
   424  	s = append(s, c.featureSet.Strings()...)
   425  	return s
   426  }
   427  
   428  // RTCounter returns the 64-bit time-stamp counter
   429  // Uses the RDTSCP instruction. The value 0 is returned
   430  // if the CPU does not support the instruction.
   431  func (c CPUInfo) RTCounter() uint64 {
   432  	if !c.Supports(RDTSCP) {
   433  		return 0
   434  	}
   435  	a, _, _, d := rdtscpAsm()
   436  	return uint64(a) | (uint64(d) << 32)
   437  }
   438  
   439  // Ia32TscAux returns the IA32_TSC_AUX part of the RDTSCP.
   440  // This variable is OS dependent, but on Linux contains information
   441  // about the current cpu/core the code is running on.
   442  // If the RDTSCP instruction isn't supported on the CPU, the value 0 is returned.
   443  func (c CPUInfo) Ia32TscAux() uint32 {
   444  	if !c.Supports(RDTSCP) {
   445  		return 0
   446  	}
   447  	_, _, ecx, _ := rdtscpAsm()
   448  	return ecx
   449  }
   450  
   451  // LogicalCPU will return the Logical CPU the code is currently executing on.
   452  // This is likely to change when the OS re-schedules the running thread
   453  // to another CPU.
   454  // If the current core cannot be detected, -1 will be returned.
   455  func (c CPUInfo) LogicalCPU() int {
   456  	if c.maxFunc < 1 {
   457  		return -1
   458  	}
   459  	_, ebx, _, _ := cpuid(1)
   460  	return int(ebx >> 24)
   461  }
   462  
   463  // frequencies tries to compute the clock speed of the CPU. If leaf 15 is
   464  // supported, use it, otherwise parse the brand string. Yes, really.
   465  func (c *CPUInfo) frequencies() {
   466  	c.Hz, c.BoostFreq = 0, 0
   467  	mfi := maxFunctionID()
   468  	if mfi >= 0x15 {
   469  		eax, ebx, ecx, _ := cpuid(0x15)
   470  		if eax != 0 && ebx != 0 && ecx != 0 {
   471  			c.Hz = (int64(ecx) * int64(ebx)) / int64(eax)
   472  		}
   473  	}
   474  	if mfi >= 0x16 {
   475  		a, b, _, _ := cpuid(0x16)
   476  		// Base...
   477  		if a&0xffff > 0 {
   478  			c.Hz = int64(a&0xffff) * 1_000_000
   479  		}
   480  		// Boost...
   481  		if b&0xffff > 0 {
   482  			c.BoostFreq = int64(b&0xffff) * 1_000_000
   483  		}
   484  	}
   485  	if c.Hz > 0 {
   486  		return
   487  	}
   488  
   489  	// computeHz determines the official rated speed of a CPU from its brand
   490  	// string. This insanity is *actually the official documented way to do
   491  	// this according to Intel*, prior to leaf 0x15 existing. The official
   492  	// documentation only shows this working for exactly `x.xx` or `xxxx`
   493  	// cases, e.g., `2.50GHz` or `1300MHz`; this parser will accept other
   494  	// sizes.
   495  	model := c.BrandName
   496  	hz := strings.LastIndex(model, "Hz")
   497  	if hz < 3 {
   498  		return
   499  	}
   500  	var multiplier int64
   501  	switch model[hz-1] {
   502  	case 'M':
   503  		multiplier = 1000 * 1000
   504  	case 'G':
   505  		multiplier = 1000 * 1000 * 1000
   506  	case 'T':
   507  		multiplier = 1000 * 1000 * 1000 * 1000
   508  	}
   509  	if multiplier == 0 {
   510  		return
   511  	}
   512  	freq := int64(0)
   513  	divisor := int64(0)
   514  	decimalShift := int64(1)
   515  	var i int
   516  	for i = hz - 2; i >= 0 && model[i] != ' '; i-- {
   517  		if model[i] >= '0' && model[i] <= '9' {
   518  			freq += int64(model[i]-'0') * decimalShift
   519  			decimalShift *= 10
   520  		} else if model[i] == '.' {
   521  			if divisor != 0 {
   522  				return
   523  			}
   524  			divisor = decimalShift
   525  		} else {
   526  			return
   527  		}
   528  	}
   529  	// we didn't find a space
   530  	if i < 0 {
   531  		return
   532  	}
   533  	if divisor != 0 {
   534  		c.Hz = (freq * multiplier) / divisor
   535  		return
   536  	}
   537  	c.Hz = freq * multiplier
   538  }
   539  
   540  // VM Will return true if the cpu id indicates we are in
   541  // a virtual machine.
   542  func (c CPUInfo) VM() bool {
   543  	return CPU.featureSet.inSet(HYPERVISOR)
   544  }
   545  
   546  // flags contains detected cpu features and characteristics
   547  type flags uint64
   548  
   549  // log2(bits_in_uint64)
   550  const flagBitsLog2 = 6
   551  const flagBits = 1 << flagBitsLog2
   552  const flagMask = flagBits - 1
   553  
   554  // flagSet contains detected cpu features and characteristics in an array of flags
   555  type flagSet [(lastID + flagMask) / flagBits]flags
   556  
   557  func (s flagSet) inSet(feat FeatureID) bool {
   558  	return s[feat>>flagBitsLog2]&(1<<(feat&flagMask)) != 0
   559  }
   560  
   561  func (s *flagSet) set(feat FeatureID) {
   562  	s[feat>>flagBitsLog2] |= 1 << (feat & flagMask)
   563  }
   564  
   565  // setIf will set a feature if boolean is true.
   566  func (s *flagSet) setIf(cond bool, features ...FeatureID) {
   567  	if cond {
   568  		for _, offset := range features {
   569  			s[offset>>flagBitsLog2] |= 1 << (offset & flagMask)
   570  		}
   571  	}
   572  }
   573  
   574  func (s *flagSet) unset(offset FeatureID) {
   575  	bit := flags(1 << (offset & flagMask))
   576  	s[offset>>flagBitsLog2] = s[offset>>flagBitsLog2] & ^bit
   577  }
   578  
   579  // or with another flagset.
   580  func (s *flagSet) or(other flagSet) {
   581  	for i, v := range other[:] {
   582  		s[i] |= v
   583  	}
   584  }
   585  
   586  // hasSet returns whether all features are present.
   587  func (s flagSet) hasSet(other flagSet) bool {
   588  	for i, v := range other[:] {
   589  		if s[i]&v != v {
   590  			return false
   591  		}
   592  	}
   593  	return true
   594  }
   595  
   596  // nEnabled will return the number of enabled flags.
   597  func (s flagSet) nEnabled() (n int) {
   598  	for _, v := range s[:] {
   599  		n += bits.OnesCount64(uint64(v))
   600  	}
   601  	return n
   602  }
   603  
   604  func flagSetWith(feat ...FeatureID) flagSet {
   605  	var res flagSet
   606  	for _, f := range feat {
   607  		res.set(f)
   608  	}
   609  	return res
   610  }
   611  
   612  // ParseFeature will parse the string and return the ID of the matching feature.
   613  // Will return UNKNOWN if not found.
   614  func ParseFeature(s string) FeatureID {
   615  	s = strings.ToUpper(s)
   616  	for i := firstID; i < lastID; i++ {
   617  		if i.String() == s {
   618  			return i
   619  		}
   620  	}
   621  	return UNKNOWN
   622  }
   623  
   624  // Strings returns an array of the detected features for FlagsSet.
   625  func (s flagSet) Strings() []string {
   626  	if len(s) == 0 {
   627  		return []string{""}
   628  	}
   629  	r := make([]string, 0)
   630  	for i := firstID; i < lastID; i++ {
   631  		if s.inSet(i) {
   632  			r = append(r, i.String())
   633  		}
   634  	}
   635  	return r
   636  }
   637  
   638  func maxExtendedFunction() uint32 {
   639  	eax, _, _, _ := cpuid(0x80000000)
   640  	return eax
   641  }
   642  
   643  func maxFunctionID() uint32 {
   644  	a, _, _, _ := cpuid(0)
   645  	return a
   646  }
   647  
   648  func brandName() string {
   649  	if maxExtendedFunction() >= 0x80000004 {
   650  		v := make([]uint32, 0, 48)
   651  		for i := uint32(0); i < 3; i++ {
   652  			a, b, c, d := cpuid(0x80000002 + i)
   653  			v = append(v, a, b, c, d)
   654  		}
   655  		return strings.Trim(string(valAsString(v...)), " ")
   656  	}
   657  	return "unknown"
   658  }
   659  
   660  func threadsPerCore() int {
   661  	mfi := maxFunctionID()
   662  	vend, _ := vendorID()
   663  
   664  	if mfi < 0x4 || (vend != Intel && vend != AMD) {
   665  		return 1
   666  	}
   667  
   668  	if mfi < 0xb {
   669  		if vend != Intel {
   670  			return 1
   671  		}
   672  		_, b, _, d := cpuid(1)
   673  		if (d & (1 << 28)) != 0 {
   674  			// v will contain logical core count
   675  			v := (b >> 16) & 255
   676  			if v > 1 {
   677  				a4, _, _, _ := cpuid(4)
   678  				// physical cores
   679  				v2 := (a4 >> 26) + 1
   680  				if v2 > 0 {
   681  					return int(v) / int(v2)
   682  				}
   683  			}
   684  		}
   685  		return 1
   686  	}
   687  	_, b, _, _ := cpuidex(0xb, 0)
   688  	if b&0xffff == 0 {
   689  		if vend == AMD {
   690  			// Workaround for AMD returning 0, assume 2 if >= Zen 2
   691  			// It will be more correct than not.
   692  			fam, _, _ := familyModel()
   693  			_, _, _, d := cpuid(1)
   694  			if (d&(1<<28)) != 0 && fam >= 23 {
   695  				return 2
   696  			}
   697  		}
   698  		return 1
   699  	}
   700  	return int(b & 0xffff)
   701  }
   702  
   703  func logicalCores() int {
   704  	mfi := maxFunctionID()
   705  	v, _ := vendorID()
   706  	switch v {
   707  	case Intel:
   708  		// Use this on old Intel processors
   709  		if mfi < 0xb {
   710  			if mfi < 1 {
   711  				return 0
   712  			}
   713  			// CPUID.1:EBX[23:16] represents the maximum number of addressable IDs (initial APIC ID)
   714  			// that can be assigned to logical processors in a physical package.
   715  			// The value may not be the same as the number of logical processors that are present in the hardware of a physical package.
   716  			_, ebx, _, _ := cpuid(1)
   717  			logical := (ebx >> 16) & 0xff
   718  			return int(logical)
   719  		}
   720  		_, b, _, _ := cpuidex(0xb, 1)
   721  		return int(b & 0xffff)
   722  	case AMD, Hygon:
   723  		_, b, _, _ := cpuid(1)
   724  		return int((b >> 16) & 0xff)
   725  	default:
   726  		return 0
   727  	}
   728  }
   729  
   730  func familyModel() (family, model, stepping int) {
   731  	if maxFunctionID() < 0x1 {
   732  		return 0, 0, 0
   733  	}
   734  	eax, _, _, _ := cpuid(1)
   735  	// If BaseFamily[3:0] is less than Fh then ExtendedFamily[7:0] is reserved and Family is equal to BaseFamily[3:0].
   736  	family = int((eax >> 8) & 0xf)
   737  	extFam := family == 0x6 // Intel is 0x6, needs extended model.
   738  	if family == 0xf {
   739  		// Add ExtFamily
   740  		family += int((eax >> 20) & 0xff)
   741  		extFam = true
   742  	}
   743  	// If BaseFamily[3:0] is less than 0Fh then ExtendedModel[3:0] is reserved and Model is equal to BaseModel[3:0].
   744  	model = int((eax >> 4) & 0xf)
   745  	if extFam {
   746  		// Add ExtModel
   747  		model += int((eax >> 12) & 0xf0)
   748  	}
   749  	stepping = int(eax & 0xf)
   750  	return family, model, stepping
   751  }
   752  
   753  func physicalCores() int {
   754  	v, _ := vendorID()
   755  	switch v {
   756  	case Intel:
   757  		return logicalCores() / threadsPerCore()
   758  	case AMD, Hygon:
   759  		lc := logicalCores()
   760  		tpc := threadsPerCore()
   761  		if lc > 0 && tpc > 0 {
   762  			return lc / tpc
   763  		}
   764  
   765  		// The following is inaccurate on AMD EPYC 7742 64-Core Processor
   766  		if maxExtendedFunction() >= 0x80000008 {
   767  			_, _, c, _ := cpuid(0x80000008)
   768  			if c&0xff > 0 {
   769  				return int(c&0xff) + 1
   770  			}
   771  		}
   772  	}
   773  	return 0
   774  }
   775  
   776  // Except from http://en.wikipedia.org/wiki/CPUID#EAX.3D0:_Get_vendor_ID
   777  var vendorMapping = map[string]Vendor{
   778  	"AMDisbetter!": AMD,
   779  	"AuthenticAMD": AMD,
   780  	"CentaurHauls": VIA,
   781  	"GenuineIntel": Intel,
   782  	"TransmetaCPU": Transmeta,
   783  	"GenuineTMx86": Transmeta,
   784  	"Geode by NSC": NSC,
   785  	"VIA VIA VIA ": VIA,
   786  	"KVMKVMKVMKVM": KVM,
   787  	"Microsoft Hv": MSVM,
   788  	"VMwareVMware": VMware,
   789  	"XenVMMXenVMM": XenHVM,
   790  	"bhyve bhyve ": Bhyve,
   791  	"HygonGenuine": Hygon,
   792  	"Vortex86 SoC": SiS,
   793  	"SiS SiS SiS ": SiS,
   794  	"RiseRiseRise": SiS,
   795  	"Genuine  RDC": RDC,
   796  }
   797  
   798  func vendorID() (Vendor, string) {
   799  	_, b, c, d := cpuid(0)
   800  	v := string(valAsString(b, d, c))
   801  	vend, ok := vendorMapping[v]
   802  	if !ok {
   803  		return VendorUnknown, v
   804  	}
   805  	return vend, v
   806  }
   807  
   808  func cacheLine() int {
   809  	if maxFunctionID() < 0x1 {
   810  		return 0
   811  	}
   812  
   813  	_, ebx, _, _ := cpuid(1)
   814  	cache := (ebx & 0xff00) >> 5 // cflush size
   815  	if cache == 0 && maxExtendedFunction() >= 0x80000006 {
   816  		_, _, ecx, _ := cpuid(0x80000006)
   817  		cache = ecx & 0xff // cacheline size
   818  	}
   819  	// TODO: Read from Cache and TLB Information
   820  	return int(cache)
   821  }
   822  
   823  func (c *CPUInfo) cacheSize() {
   824  	c.Cache.L1D = -1
   825  	c.Cache.L1I = -1
   826  	c.Cache.L2 = -1
   827  	c.Cache.L3 = -1
   828  	vendor, _ := vendorID()
   829  	switch vendor {
   830  	case Intel:
   831  		if maxFunctionID() < 4 {
   832  			return
   833  		}
   834  		c.Cache.L1I, c.Cache.L1D, c.Cache.L2, c.Cache.L3 = 0, 0, 0, 0
   835  		for i := uint32(0); ; i++ {
   836  			eax, ebx, ecx, _ := cpuidex(4, i)
   837  			cacheType := eax & 15
   838  			if cacheType == 0 {
   839  				break
   840  			}
   841  			cacheLevel := (eax >> 5) & 7
   842  			coherency := int(ebx&0xfff) + 1
   843  			partitions := int((ebx>>12)&0x3ff) + 1
   844  			associativity := int((ebx>>22)&0x3ff) + 1
   845  			sets := int(ecx) + 1
   846  			size := associativity * partitions * coherency * sets
   847  			switch cacheLevel {
   848  			case 1:
   849  				if cacheType == 1 {
   850  					// 1 = Data Cache
   851  					c.Cache.L1D = size
   852  				} else if cacheType == 2 {
   853  					// 2 = Instruction Cache
   854  					c.Cache.L1I = size
   855  				} else {
   856  					if c.Cache.L1D < 0 {
   857  						c.Cache.L1I = size
   858  					}
   859  					if c.Cache.L1I < 0 {
   860  						c.Cache.L1I = size
   861  					}
   862  				}
   863  			case 2:
   864  				c.Cache.L2 = size
   865  			case 3:
   866  				c.Cache.L3 = size
   867  			}
   868  		}
   869  	case AMD, Hygon:
   870  		// Untested.
   871  		if maxExtendedFunction() < 0x80000005 {
   872  			return
   873  		}
   874  		_, _, ecx, edx := cpuid(0x80000005)
   875  		c.Cache.L1D = int(((ecx >> 24) & 0xFF) * 1024)
   876  		c.Cache.L1I = int(((edx >> 24) & 0xFF) * 1024)
   877  
   878  		if maxExtendedFunction() < 0x80000006 {
   879  			return
   880  		}
   881  		_, _, ecx, _ = cpuid(0x80000006)
   882  		c.Cache.L2 = int(((ecx >> 16) & 0xFFFF) * 1024)
   883  
   884  		// CPUID Fn8000_001D_EAX_x[N:0] Cache Properties
   885  		if maxExtendedFunction() < 0x8000001D {
   886  			return
   887  		}
   888  
   889  		// Xen Hypervisor is buggy and returns the same entry no matter ECX value.
   890  		// Hack: When we encounter the same entry 100 times we break.
   891  		nSame := 0
   892  		var last uint32
   893  		for i := uint32(0); i < math.MaxUint32; i++ {
   894  			eax, ebx, ecx, _ := cpuidex(0x8000001D, i)
   895  
   896  			level := (eax >> 5) & 7
   897  			cacheNumSets := ecx + 1
   898  			cacheLineSize := 1 + (ebx & 2047)
   899  			cachePhysPartitions := 1 + ((ebx >> 12) & 511)
   900  			cacheNumWays := 1 + ((ebx >> 22) & 511)
   901  
   902  			typ := eax & 15
   903  			size := int(cacheNumSets * cacheLineSize * cachePhysPartitions * cacheNumWays)
   904  			if typ == 0 {
   905  				return
   906  			}
   907  
   908  			// Check for the same value repeated.
   909  			comb := eax ^ ebx ^ ecx
   910  			if comb == last {
   911  				nSame++
   912  				if nSame == 100 {
   913  					return
   914  				}
   915  			}
   916  			last = comb
   917  
   918  			switch level {
   919  			case 1:
   920  				switch typ {
   921  				case 1:
   922  					// Data cache
   923  					c.Cache.L1D = size
   924  				case 2:
   925  					// Inst cache
   926  					c.Cache.L1I = size
   927  				default:
   928  					if c.Cache.L1D < 0 {
   929  						c.Cache.L1I = size
   930  					}
   931  					if c.Cache.L1I < 0 {
   932  						c.Cache.L1I = size
   933  					}
   934  				}
   935  			case 2:
   936  				c.Cache.L2 = size
   937  			case 3:
   938  				c.Cache.L3 = size
   939  			}
   940  		}
   941  	}
   942  }
   943  
   944  type SGXEPCSection struct {
   945  	BaseAddress uint64
   946  	EPCSize     uint64
   947  }
   948  
   949  type SGXSupport struct {
   950  	Available           bool
   951  	LaunchControl       bool
   952  	SGX1Supported       bool
   953  	SGX2Supported       bool
   954  	MaxEnclaveSizeNot64 int64
   955  	MaxEnclaveSize64    int64
   956  	EPCSections         []SGXEPCSection
   957  }
   958  
   959  func hasSGX(available, lc bool) (rval SGXSupport) {
   960  	rval.Available = available
   961  
   962  	if !available {
   963  		return
   964  	}
   965  
   966  	rval.LaunchControl = lc
   967  
   968  	a, _, _, d := cpuidex(0x12, 0)
   969  	rval.SGX1Supported = a&0x01 != 0
   970  	rval.SGX2Supported = a&0x02 != 0
   971  	rval.MaxEnclaveSizeNot64 = 1 << (d & 0xFF)     // pow 2
   972  	rval.MaxEnclaveSize64 = 1 << ((d >> 8) & 0xFF) // pow 2
   973  	rval.EPCSections = make([]SGXEPCSection, 0)
   974  
   975  	for subleaf := uint32(2); subleaf < 2+8; subleaf++ {
   976  		eax, ebx, ecx, edx := cpuidex(0x12, subleaf)
   977  		leafType := eax & 0xf
   978  
   979  		if leafType == 0 {
   980  			// Invalid subleaf, stop iterating
   981  			break
   982  		} else if leafType == 1 {
   983  			// EPC Section subleaf
   984  			baseAddress := uint64(eax&0xfffff000) + (uint64(ebx&0x000fffff) << 32)
   985  			size := uint64(ecx&0xfffff000) + (uint64(edx&0x000fffff) << 32)
   986  
   987  			section := SGXEPCSection{BaseAddress: baseAddress, EPCSize: size}
   988  			rval.EPCSections = append(rval.EPCSections, section)
   989  		}
   990  	}
   991  
   992  	return
   993  }
   994  
   995  func support() flagSet {
   996  	var fs flagSet
   997  	mfi := maxFunctionID()
   998  	vend, _ := vendorID()
   999  	if mfi < 0x1 {
  1000  		return fs
  1001  	}
  1002  	family, model, _ := familyModel()
  1003  
  1004  	_, _, c, d := cpuid(1)
  1005  	fs.setIf((d&(1<<0)) != 0, X87)
  1006  	fs.setIf((d&(1<<8)) != 0, CMPXCHG8)
  1007  	fs.setIf((d&(1<<11)) != 0, SYSEE)
  1008  	fs.setIf((d&(1<<15)) != 0, CMOV)
  1009  	fs.setIf((d&(1<<23)) != 0, MMX)
  1010  	fs.setIf((d&(1<<24)) != 0, FXSR)
  1011  	fs.setIf((d&(1<<25)) != 0, FXSROPT)
  1012  	fs.setIf((d&(1<<25)) != 0, SSE)
  1013  	fs.setIf((d&(1<<26)) != 0, SSE2)
  1014  	fs.setIf((c&1) != 0, SSE3)
  1015  	fs.setIf((c&(1<<5)) != 0, VMX)
  1016  	fs.setIf((c&(1<<9)) != 0, SSSE3)
  1017  	fs.setIf((c&(1<<19)) != 0, SSE4)
  1018  	fs.setIf((c&(1<<20)) != 0, SSE42)
  1019  	fs.setIf((c&(1<<25)) != 0, AESNI)
  1020  	fs.setIf((c&(1<<1)) != 0, CLMUL)
  1021  	fs.setIf(c&(1<<22) != 0, MOVBE)
  1022  	fs.setIf(c&(1<<23) != 0, POPCNT)
  1023  	fs.setIf(c&(1<<30) != 0, RDRAND)
  1024  
  1025  	// This bit has been reserved by Intel & AMD for use by hypervisors,
  1026  	// and indicates the presence of a hypervisor.
  1027  	fs.setIf(c&(1<<31) != 0, HYPERVISOR)
  1028  	fs.setIf(c&(1<<29) != 0, F16C)
  1029  	fs.setIf(c&(1<<13) != 0, CX16)
  1030  
  1031  	if vend == Intel && (d&(1<<28)) != 0 && mfi >= 4 {
  1032  		fs.setIf(threadsPerCore() > 1, HTT)
  1033  	}
  1034  	if vend == AMD && (d&(1<<28)) != 0 && mfi >= 4 {
  1035  		fs.setIf(threadsPerCore() > 1, HTT)
  1036  	}
  1037  	fs.setIf(c&1<<26 != 0, XSAVE)
  1038  	fs.setIf(c&1<<27 != 0, OSXSAVE)
  1039  	// Check XGETBV/XSAVE (26), OXSAVE (27) and AVX (28) bits
  1040  	const avxCheck = 1<<26 | 1<<27 | 1<<28
  1041  	if c&avxCheck == avxCheck {
  1042  		// Check for OS support
  1043  		eax, _ := xgetbv(0)
  1044  		if (eax & 0x6) == 0x6 {
  1045  			fs.set(AVX)
  1046  			switch vend {
  1047  			case Intel:
  1048  				// Older than Haswell.
  1049  				fs.setIf(family == 6 && model < 60, AVXSLOW)
  1050  			case AMD:
  1051  				// Older than Zen 2
  1052  				fs.setIf(family < 23 || (family == 23 && model < 49), AVXSLOW)
  1053  			}
  1054  		}
  1055  	}
  1056  	// FMA3 can be used with SSE registers, so no OS support is strictly needed.
  1057  	// fma3 and OSXSAVE needed.
  1058  	const fma3Check = 1<<12 | 1<<27
  1059  	fs.setIf(c&fma3Check == fma3Check, FMA3)
  1060  
  1061  	// Check AVX2, AVX2 requires OS support, but BMI1/2 don't.
  1062  	if mfi >= 7 {
  1063  		_, ebx, ecx, edx := cpuidex(7, 0)
  1064  		if fs.inSet(AVX) && (ebx&0x00000020) != 0 {
  1065  			fs.set(AVX2)
  1066  		}
  1067  		// CPUID.(EAX=7, ECX=0).EBX
  1068  		if (ebx & 0x00000008) != 0 {
  1069  			fs.set(BMI1)
  1070  			fs.setIf((ebx&0x00000100) != 0, BMI2)
  1071  		}
  1072  		fs.setIf(ebx&(1<<2) != 0, SGX)
  1073  		fs.setIf(ebx&(1<<4) != 0, HLE)
  1074  		fs.setIf(ebx&(1<<9) != 0, ERMS)
  1075  		fs.setIf(ebx&(1<<11) != 0, RTM)
  1076  		fs.setIf(ebx&(1<<14) != 0, MPX)
  1077  		fs.setIf(ebx&(1<<18) != 0, RDSEED)
  1078  		fs.setIf(ebx&(1<<19) != 0, ADX)
  1079  		fs.setIf(ebx&(1<<29) != 0, SHA)
  1080  
  1081  		// CPUID.(EAX=7, ECX=0).ECX
  1082  		fs.setIf(ecx&(1<<5) != 0, WAITPKG)
  1083  		fs.setIf(ecx&(1<<7) != 0, CETSS)
  1084  		fs.setIf(ecx&(1<<8) != 0, GFNI)
  1085  		fs.setIf(ecx&(1<<9) != 0, VAES)
  1086  		fs.setIf(ecx&(1<<10) != 0, VPCLMULQDQ)
  1087  		fs.setIf(ecx&(1<<13) != 0, TME)
  1088  		fs.setIf(ecx&(1<<25) != 0, CLDEMOTE)
  1089  		fs.setIf(ecx&(1<<27) != 0, MOVDIRI)
  1090  		fs.setIf(ecx&(1<<28) != 0, MOVDIR64B)
  1091  		fs.setIf(ecx&(1<<29) != 0, ENQCMD)
  1092  		fs.setIf(ecx&(1<<30) != 0, SGXLC)
  1093  
  1094  		// CPUID.(EAX=7, ECX=0).EDX
  1095  		fs.setIf(edx&(1<<11) != 0, RTM_ALWAYS_ABORT)
  1096  		fs.setIf(edx&(1<<14) != 0, SERIALIZE)
  1097  		fs.setIf(edx&(1<<16) != 0, TSXLDTRK)
  1098  		fs.setIf(edx&(1<<18) != 0, PCONFIG)
  1099  		fs.setIf(edx&(1<<20) != 0, CETIBT)
  1100  		fs.setIf(edx&(1<<26) != 0, IBPB)
  1101  		fs.setIf(edx&(1<<27) != 0, STIBP)
  1102  
  1103  		// CPUID.(EAX=7, ECX=1)
  1104  		eax1, _, _, _ := cpuidex(7, 1)
  1105  		fs.setIf(fs.inSet(AVX) && eax1&(1<<4) != 0, AVXVNNI)
  1106  		fs.setIf(eax1&(1<<10) != 0, MOVSB_ZL)
  1107  		fs.setIf(eax1&(1<<11) != 0, STOSB_SHORT)
  1108  		fs.setIf(eax1&(1<<12) != 0, CMPSB_SCADBS_SHORT)
  1109  		fs.setIf(eax1&(1<<22) != 0, HRESET)
  1110  		fs.setIf(eax1&(1<<26) != 0, LAM)
  1111  
  1112  		// Only detect AVX-512 features if XGETBV is supported
  1113  		if c&((1<<26)|(1<<27)) == (1<<26)|(1<<27) {
  1114  			// Check for OS support
  1115  			eax, _ := xgetbv(0)
  1116  
  1117  			// Verify that XCR0[7:5] = ‘111b’ (OPMASK state, upper 256-bit of ZMM0-ZMM15 and
  1118  			// ZMM16-ZMM31 state are enabled by OS)
  1119  			/// and that XCR0[2:1] = ‘11b’ (XMM state and YMM state are enabled by OS).
  1120  			hasAVX512 := (eax>>5)&7 == 7 && (eax>>1)&3 == 3
  1121  			if runtime.GOOS == "darwin" {
  1122  				hasAVX512 = fs.inSet(AVX) && darwinHasAVX512()
  1123  			}
  1124  			if hasAVX512 {
  1125  				fs.setIf(ebx&(1<<16) != 0, AVX512F)
  1126  				fs.setIf(ebx&(1<<17) != 0, AVX512DQ)
  1127  				fs.setIf(ebx&(1<<21) != 0, AVX512IFMA)
  1128  				fs.setIf(ebx&(1<<26) != 0, AVX512PF)
  1129  				fs.setIf(ebx&(1<<27) != 0, AVX512ER)
  1130  				fs.setIf(ebx&(1<<28) != 0, AVX512CD)
  1131  				fs.setIf(ebx&(1<<30) != 0, AVX512BW)
  1132  				fs.setIf(ebx&(1<<31) != 0, AVX512VL)
  1133  				// ecx
  1134  				fs.setIf(ecx&(1<<1) != 0, AVX512VBMI)
  1135  				fs.setIf(ecx&(1<<6) != 0, AVX512VBMI2)
  1136  				fs.setIf(ecx&(1<<11) != 0, AVX512VNNI)
  1137  				fs.setIf(ecx&(1<<12) != 0, AVX512BITALG)
  1138  				fs.setIf(ecx&(1<<14) != 0, AVX512VPOPCNTDQ)
  1139  				// edx
  1140  				fs.setIf(edx&(1<<8) != 0, AVX512VP2INTERSECT)
  1141  				fs.setIf(edx&(1<<22) != 0, AMXBF16)
  1142  				fs.setIf(edx&(1<<23) != 0, AVX512FP16)
  1143  				fs.setIf(edx&(1<<24) != 0, AMXTILE)
  1144  				fs.setIf(edx&(1<<25) != 0, AMXINT8)
  1145  				// eax1 = CPUID.(EAX=7, ECX=1).EAX
  1146  				fs.setIf(eax1&(1<<5) != 0, AVX512BF16)
  1147  			}
  1148  		}
  1149  	}
  1150  	// Processor Extended State Enumeration Sub-leaf (EAX = 0DH, ECX = 1)
  1151  	// EAX
  1152  	// Bit 00: XSAVEOPT is available.
  1153  	// Bit 01: Supports XSAVEC and the compacted form of XRSTOR if set.
  1154  	// Bit 02: Supports XGETBV with ECX = 1 if set.
  1155  	// Bit 03: Supports XSAVES/XRSTORS and IA32_XSS if set.
  1156  	// Bits 31 - 04: Reserved.
  1157  	// EBX
  1158  	// Bits 31 - 00: The size in bytes of the XSAVE area containing all states enabled by XCRO | IA32_XSS.
  1159  	// ECX
  1160  	// Bits 31 - 00: Reports the supported bits of the lower 32 bits of the IA32_XSS MSR. IA32_XSS[n] can be set to 1 only if ECX[n] is 1.
  1161  	// EDX?
  1162  	// Bits 07 - 00: Used for XCR0. Bit 08: PT state. Bit 09: Used for XCR0. Bits 12 - 10: Reserved. Bit 13: HWP state. Bits 31 - 14: Reserved.
  1163  	if mfi >= 0xd {
  1164  		if fs.inSet(XSAVE) {
  1165  			eax, _, _, _ := cpuidex(0xd, 1)
  1166  			fs.setIf(eax&(1<<0) != 0, XSAVEOPT)
  1167  			fs.setIf(eax&(1<<1) != 0, XSAVEC)
  1168  			fs.setIf(eax&(1<<2) != 0, XGETBV1)
  1169  			fs.setIf(eax&(1<<3) != 0, XSAVES)
  1170  		}
  1171  	}
  1172  	if maxExtendedFunction() >= 0x80000001 {
  1173  		_, _, c, d := cpuid(0x80000001)
  1174  		if (c & (1 << 5)) != 0 {
  1175  			fs.set(LZCNT)
  1176  			fs.set(POPCNT)
  1177  		}
  1178  		// ECX
  1179  		fs.setIf((c&(1<<0)) != 0, LAHF)
  1180  		fs.setIf((c&(1<<2)) != 0, SVM)
  1181  		fs.setIf((c&(1<<6)) != 0, SSE4A)
  1182  		fs.setIf((c&(1<<10)) != 0, IBS)
  1183  
  1184  		// EDX
  1185  		fs.setIf(d&(1<<11) != 0, SYSCALL)
  1186  		fs.setIf(d&(1<<20) != 0, NX)
  1187  		fs.setIf(d&(1<<22) != 0, MMXEXT)
  1188  		fs.setIf(d&(1<<23) != 0, MMX)
  1189  		fs.setIf(d&(1<<24) != 0, FXSR)
  1190  		fs.setIf(d&(1<<25) != 0, FXSROPT)
  1191  		fs.setIf(d&(1<<27) != 0, RDTSCP)
  1192  		fs.setIf(d&(1<<30) != 0, AMD3DNOWEXT)
  1193  		fs.setIf(d&(1<<31) != 0, AMD3DNOW)
  1194  
  1195  		/* XOP and FMA4 use the AVX instruction coding scheme, so they can't be
  1196  		 * used unless the OS has AVX support. */
  1197  		if fs.inSet(AVX) {
  1198  			fs.setIf((c&0x00000800) != 0, XOP)
  1199  			fs.setIf((c&0x00010000) != 0, FMA4)
  1200  		}
  1201  
  1202  	}
  1203  	if maxExtendedFunction() >= 0x80000007 {
  1204  		_, b, _, d := cpuid(0x80000007)
  1205  		fs.setIf((b&(1<<0)) != 0, MCAOVERFLOW)
  1206  		fs.setIf((b&(1<<1)) != 0, SUCCOR)
  1207  		fs.setIf((b&(1<<2)) != 0, HWA)
  1208  		fs.setIf((d&(1<<9)) != 0, CPBOOST)
  1209  	}
  1210  
  1211  	if maxExtendedFunction() >= 0x80000008 {
  1212  		_, b, _, _ := cpuid(0x80000008)
  1213  		fs.setIf((b&(1<<9)) != 0, WBNOINVD)
  1214  		fs.setIf((b&(1<<8)) != 0, MCOMMIT)
  1215  		fs.setIf((b&(1<<13)) != 0, INT_WBINVD)
  1216  		fs.setIf((b&(1<<4)) != 0, RDPRU)
  1217  		fs.setIf((b&(1<<3)) != 0, INVLPGB)
  1218  		fs.setIf((b&(1<<1)) != 0, MSRIRC)
  1219  		fs.setIf((b&(1<<0)) != 0, CLZERO)
  1220  	}
  1221  
  1222  	if fs.inSet(SVM) && maxExtendedFunction() >= 0x8000000A {
  1223  		_, _, _, edx := cpuid(0x8000000A)
  1224  		fs.setIf((edx>>0)&1 == 1, SVMNP)
  1225  		fs.setIf((edx>>1)&1 == 1, LBRVIRT)
  1226  		fs.setIf((edx>>2)&1 == 1, SVML)
  1227  		fs.setIf((edx>>3)&1 == 1, NRIPS)
  1228  		fs.setIf((edx>>4)&1 == 1, TSCRATEMSR)
  1229  		fs.setIf((edx>>5)&1 == 1, VMCBCLEAN)
  1230  		fs.setIf((edx>>6)&1 == 1, SVMFBASID)
  1231  		fs.setIf((edx>>7)&1 == 1, SVMDA)
  1232  		fs.setIf((edx>>10)&1 == 1, SVMPF)
  1233  		fs.setIf((edx>>12)&1 == 1, SVMPFT)
  1234  	}
  1235  
  1236  	if maxExtendedFunction() >= 0x8000001b && fs.inSet(IBS) {
  1237  		eax, _, _, _ := cpuid(0x8000001b)
  1238  		fs.setIf((eax>>0)&1 == 1, IBSFFV)
  1239  		fs.setIf((eax>>1)&1 == 1, IBSFETCHSAM)
  1240  		fs.setIf((eax>>2)&1 == 1, IBSOPSAM)
  1241  		fs.setIf((eax>>3)&1 == 1, IBSRDWROPCNT)
  1242  		fs.setIf((eax>>4)&1 == 1, IBSOPCNT)
  1243  		fs.setIf((eax>>5)&1 == 1, IBSBRNTRGT)
  1244  		fs.setIf((eax>>6)&1 == 1, IBSOPCNTEXT)
  1245  		fs.setIf((eax>>7)&1 == 1, IBSRIPINVALIDCHK)
  1246  	}
  1247  
  1248  	if maxExtendedFunction() >= 0x8000001f && vend == AMD {
  1249  		a, _, _, _ := cpuid(0x8000001f)
  1250  		fs.setIf((a>>0)&1 == 1, SME)
  1251  		fs.setIf((a>>1)&1 == 1, SEV)
  1252  		fs.setIf((a>>2)&1 == 1, MSR_PAGEFLUSH)
  1253  		fs.setIf((a>>3)&1 == 1, SEV_ES)
  1254  		fs.setIf((a>>4)&1 == 1, SEV_SNP)
  1255  		fs.setIf((a>>5)&1 == 1, VMPL)
  1256  		fs.setIf((a>>10)&1 == 1, SME_COHERENT)
  1257  		fs.setIf((a>>11)&1 == 1, SEV_64BIT)
  1258  		fs.setIf((a>>12)&1 == 1, SEV_RESTRICTED)
  1259  		fs.setIf((a>>13)&1 == 1, SEV_ALTERNATIVE)
  1260  		fs.setIf((a>>14)&1 == 1, SEV_DEBUGSWAP)
  1261  		fs.setIf((a>>15)&1 == 1, IBS_PREVENTHOST)
  1262  		fs.setIf((a>>16)&1 == 1, VTE)
  1263  		fs.setIf((a>>24)&1 == 1, VMSA_REGPROT)
  1264  	}
  1265  
  1266  	return fs
  1267  }
  1268  
  1269  func valAsString(values ...uint32) []byte {
  1270  	r := make([]byte, 4*len(values))
  1271  	for i, v := range values {
  1272  		dst := r[i*4:]
  1273  		dst[0] = byte(v & 0xff)
  1274  		dst[1] = byte((v >> 8) & 0xff)
  1275  		dst[2] = byte((v >> 16) & 0xff)
  1276  		dst[3] = byte((v >> 24) & 0xff)
  1277  		switch {
  1278  		case dst[0] == 0:
  1279  			return r[:i*4]
  1280  		case dst[1] == 0:
  1281  			return r[:i*4+1]
  1282  		case dst[2] == 0:
  1283  			return r[:i*4+2]
  1284  		case dst[3] == 0:
  1285  			return r[:i*4+3]
  1286  		}
  1287  	}
  1288  	return r
  1289  }