cpuid.go 48 KB

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