cpuid.go 53 KB

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