cpuid.go 47 KB

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