cpuid.go 51 KB

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