1 #![no_std]
2 #![crate_name = "raw_cpuid"]
3 #![crate_type = "lib"]
4 
5 #[cfg(test)]
6 #[macro_use]
7 extern crate std;
8 
9 #[cfg(test)]
10 mod tests;
11 #[cfg(feature = "serialize")]
12 #[macro_use]
13 extern crate serde_derive;
14 
15 #[macro_use]
16 extern crate bitflags;
17 
18 /// Provides `cpuid` on stable by linking against a C implementation.
19 #[cfg(not(feature = "use_arch"))]
20 pub mod native_cpuid {
21     use super::CpuIdResult;
22 
23     extern "C" {
cpuid(a: *mut u32, b: *mut u32, c: *mut u32, d: *mut u32)24         fn cpuid(a: *mut u32, b: *mut u32, c: *mut u32, d: *mut u32);
25     }
26 
cpuid_count(mut eax: u32, mut ecx: u32) -> CpuIdResult27     pub fn cpuid_count(mut eax: u32, mut ecx: u32) -> CpuIdResult {
28         let mut ebx = 0u32;
29         let mut edx = 0u32;
30 
31         unsafe {
32             cpuid(&mut eax, &mut ebx, &mut ecx, &mut edx);
33         }
34 
35         CpuIdResult { eax, ebx, ecx, edx }
36     }
37 }
38 
39 /// Uses Rust's `cpuid` function from the `arch` module.
40 #[cfg(feature = "use_arch")]
41 pub mod native_cpuid {
42     use super::CpuIdResult;
43 
44     #[cfg(target_arch = "x86")]
45     use core::arch::x86 as arch;
46     #[cfg(target_arch = "x86_64")]
47     use core::arch::x86_64 as arch;
48 
cpuid_count(a: u32, c: u32) -> CpuIdResult49     pub fn cpuid_count(a: u32, c: u32) -> CpuIdResult {
50         let result = unsafe { self::arch::__cpuid_count(a, c) };
51 
52         CpuIdResult {
53             eax: result.eax,
54             ebx: result.ebx,
55             ecx: result.ecx,
56             edx: result.edx,
57         }
58     }
59 }
60 
61 use core::cmp::min;
62 use core::fmt;
63 use core::mem::transmute;
64 use core::slice;
65 use core::str;
66 
67 #[cfg(not(test))]
68 mod std {
69     pub use core::ops;
70     pub use core::option;
71 }
72 
73 /// Macro which queries cpuid directly.
74 ///
75 /// First parameter is cpuid leaf (EAX register value),
76 /// second optional parameter is the subleaf (ECX register value).
77 #[macro_export]
78 macro_rules! cpuid {
79     ($eax:expr) => {
80         $crate::native_cpuid::cpuid_count($eax as u32, 0)
81     };
82 
83     ($eax:expr, $ecx:expr) => {
84         $crate::native_cpuid::cpuid_count($eax as u32, $ecx as u32)
85     };
86 }
87 
as_bytes(v: &u32) -> &[u8]88 fn as_bytes(v: &u32) -> &[u8] {
89     let start = v as *const u32 as *const u8;
90     unsafe { slice::from_raw_parts(start, 4) }
91 }
92 
get_bits(r: u32, from: u32, to: u32) -> u3293 fn get_bits(r: u32, from: u32, to: u32) -> u32 {
94     assert!(from <= 31);
95     assert!(to <= 31);
96     assert!(from <= to);
97 
98     let mask = match to {
99         31 => 0xffffffff,
100         _ => (1 << (to + 1)) - 1,
101     };
102 
103     (r & mask) >> from
104 }
105 
106 macro_rules! check_flag {
107     ($doc:meta, $fun:ident, $flags:ident, $flag:expr) => (
108         #[$doc]
109         pub fn $fun(&self) -> bool {
110             self.$flags.contains($flag)
111         }
112     )
113 }
114 
115 macro_rules! is_bit_set {
116     ($field:expr, $bit:expr) => {
117         $field & (1 << $bit) > 0
118     };
119 }
120 
121 macro_rules! check_bit_fn {
122     ($doc:meta, $fun:ident, $field:ident, $bit:expr) => (
123         #[$doc]
124         pub fn $fun(&self) -> bool {
125             is_bit_set!(self.$field, $bit)
126         }
127     )
128 }
129 
130 /// Main type used to query for information about the CPU we're running on.
131 #[derive(Debug, Default)]
132 #[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))]
133 pub struct CpuId {
134     max_eax_value: u32,
135 }
136 
137 /// Low-level data-structure to store result of cpuid instruction.
138 #[derive(Copy, Clone, Debug, Default)]
139 #[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))]
140 pub struct CpuIdResult {
141     /// Return value EAX register
142     pub eax: u32,
143     /// Return value EBX register
144     pub ebx: u32,
145     /// Return value ECX register
146     pub ecx: u32,
147     /// Return value EDX register
148     pub edx: u32,
149 }
150 
151 const EAX_VENDOR_INFO: u32 = 0x0;
152 const EAX_FEATURE_INFO: u32 = 0x1;
153 const EAX_CACHE_INFO: u32 = 0x2;
154 const EAX_PROCESSOR_SERIAL: u32 = 0x3;
155 const EAX_CACHE_PARAMETERS: u32 = 0x4;
156 const EAX_MONITOR_MWAIT_INFO: u32 = 0x5;
157 const EAX_THERMAL_POWER_INFO: u32 = 0x6;
158 const EAX_STRUCTURED_EXTENDED_FEATURE_INFO: u32 = 0x7;
159 const EAX_DIRECT_CACHE_ACCESS_INFO: u32 = 0x9;
160 const EAX_PERFORMANCE_MONITOR_INFO: u32 = 0xA;
161 const EAX_EXTENDED_TOPOLOGY_INFO: u32 = 0xB;
162 const EAX_EXTENDED_STATE_INFO: u32 = 0xD;
163 const EAX_RDT_MONITORING: u32 = 0xF;
164 const EAX_RDT_ALLOCATION: u32 = 0x10;
165 const EAX_SGX: u32 = 0x12;
166 const EAX_TRACE_INFO: u32 = 0x14;
167 const EAX_TIME_STAMP_COUNTER_INFO: u32 = 0x15;
168 const EAX_FREQUENCY_INFO: u32 = 0x16;
169 const EAX_SOC_VENDOR_INFO: u32 = 0x17;
170 const EAX_DETERMINISTIC_ADDRESS_TRANSLATION_INFO: u32 = 0x18;
171 const EAX_HYPERVISOR_INFO: u32 = 0x40000000;
172 const EAX_EXTENDED_FUNCTION_INFO: u32 = 0x80000000;
173 const EAX_MEMORY_ENCRYPTION_INFO: u32 = 0x8000001F;
174 
175 impl CpuId {
176     /// Return new CPUID struct.
new() -> CpuId177     pub fn new() -> CpuId {
178         let res = cpuid!(EAX_VENDOR_INFO);
179         CpuId {
180             max_eax_value: res.eax,
181         }
182     }
183 
leaf_is_supported(&self, val: u32) -> bool184     fn leaf_is_supported(&self, val: u32) -> bool {
185         val <= self.max_eax_value
186     }
187 
188     /// Return information about vendor.
189     /// This is typically a ASCII readable string such as
190     /// GenuineIntel for Intel CPUs or AuthenticAMD for AMD CPUs.
get_vendor_info(&self) -> Option<VendorInfo>191     pub fn get_vendor_info(&self) -> Option<VendorInfo> {
192         if self.leaf_is_supported(EAX_VENDOR_INFO) {
193             let res = cpuid!(EAX_VENDOR_INFO);
194             Some(VendorInfo {
195                 ebx: res.ebx,
196                 ecx: res.ecx,
197                 edx: res.edx,
198             })
199         } else {
200             None
201         }
202     }
203 
204     /// Query a set of features that are available on this CPU.
get_feature_info(&self) -> Option<FeatureInfo>205     pub fn get_feature_info(&self) -> Option<FeatureInfo> {
206         if self.leaf_is_supported(EAX_FEATURE_INFO) {
207             let res = cpuid!(EAX_FEATURE_INFO);
208             Some(FeatureInfo {
209                 eax: res.eax,
210                 ebx: res.ebx,
211                 edx_ecx: FeatureInfoFlags {
212                     bits: (((res.edx as u64) << 32) | (res.ecx as u64)),
213                 },
214             })
215         } else {
216             None
217         }
218     }
219 
220     /// Query basic information about caches. This will just return an index
221     /// into a static table of cache descriptions (see `CACHE_INFO_TABLE`).
get_cache_info(&self) -> Option<CacheInfoIter>222     pub fn get_cache_info(&self) -> Option<CacheInfoIter> {
223         if self.leaf_is_supported(EAX_CACHE_INFO) {
224             let res = cpuid!(EAX_CACHE_INFO);
225             Some(CacheInfoIter {
226                 current: 1,
227                 eax: res.eax,
228                 ebx: res.ebx,
229                 ecx: res.ecx,
230                 edx: res.edx,
231             })
232         } else {
233             None
234         }
235     }
236 
237     /// Retrieve serial number of processor.
get_processor_serial(&self) -> Option<ProcessorSerial>238     pub fn get_processor_serial(&self) -> Option<ProcessorSerial> {
239         if self.leaf_is_supported(EAX_PROCESSOR_SERIAL) {
240             let res = cpuid!(EAX_PROCESSOR_SERIAL);
241             Some(ProcessorSerial {
242                 ecx: res.ecx,
243                 edx: res.edx,
244             })
245         } else {
246             None
247         }
248     }
249 
250     /// Retrieve more elaborate information about caches (as opposed
251     /// to `get_cache_info`). This will tell us about associativity,
252     /// set size, line size etc. for each level of the cache hierarchy.
get_cache_parameters(&self) -> Option<CacheParametersIter>253     pub fn get_cache_parameters(&self) -> Option<CacheParametersIter> {
254         if self.leaf_is_supported(EAX_CACHE_PARAMETERS) {
255             Some(CacheParametersIter { current: 0 })
256         } else {
257             None
258         }
259     }
260 
261     /// Information about how monitor/mwait works on this CPU.
get_monitor_mwait_info(&self) -> Option<MonitorMwaitInfo>262     pub fn get_monitor_mwait_info(&self) -> Option<MonitorMwaitInfo> {
263         if self.leaf_is_supported(EAX_MONITOR_MWAIT_INFO) {
264             let res = cpuid!(EAX_MONITOR_MWAIT_INFO);
265             Some(MonitorMwaitInfo {
266                 eax: res.eax,
267                 ebx: res.ebx,
268                 ecx: res.ecx,
269                 edx: res.edx,
270             })
271         } else {
272             None
273         }
274     }
275 
276     /// Query information about thermal and power management features of the CPU.
get_thermal_power_info(&self) -> Option<ThermalPowerInfo>277     pub fn get_thermal_power_info(&self) -> Option<ThermalPowerInfo> {
278         if self.leaf_is_supported(EAX_THERMAL_POWER_INFO) {
279             let res = cpuid!(EAX_THERMAL_POWER_INFO);
280             Some(ThermalPowerInfo {
281                 eax: ThermalPowerFeaturesEax { bits: res.eax },
282                 ebx: res.ebx,
283                 ecx: ThermalPowerFeaturesEcx { bits: res.ecx },
284                 edx: res.edx,
285             })
286         } else {
287             None
288         }
289     }
290 
291     /// Find out about more features supported by this CPU.
get_extended_feature_info(&self) -> Option<ExtendedFeatures>292     pub fn get_extended_feature_info(&self) -> Option<ExtendedFeatures> {
293         if self.leaf_is_supported(EAX_STRUCTURED_EXTENDED_FEATURE_INFO) {
294             let res = cpuid!(EAX_STRUCTURED_EXTENDED_FEATURE_INFO);
295             assert!(res.eax == 0);
296             Some(ExtendedFeatures {
297                 eax: res.eax,
298                 ebx: ExtendedFeaturesEbx { bits: res.ebx },
299                 ecx: ExtendedFeaturesEcx { bits: res.ecx },
300                 edx: res.edx,
301             })
302         } else {
303             None
304         }
305     }
306 
307     /// Direct cache access info.
get_direct_cache_access_info(&self) -> Option<DirectCacheAccessInfo>308     pub fn get_direct_cache_access_info(&self) -> Option<DirectCacheAccessInfo> {
309         if self.leaf_is_supported(EAX_DIRECT_CACHE_ACCESS_INFO) {
310             let res = cpuid!(EAX_DIRECT_CACHE_ACCESS_INFO);
311             Some(DirectCacheAccessInfo { eax: res.eax })
312         } else {
313             None
314         }
315     }
316 
317     /// Info about performance monitoring (how many counters etc.).
get_performance_monitoring_info(&self) -> Option<PerformanceMonitoringInfo>318     pub fn get_performance_monitoring_info(&self) -> Option<PerformanceMonitoringInfo> {
319         if self.leaf_is_supported(EAX_PERFORMANCE_MONITOR_INFO) {
320             let res = cpuid!(EAX_PERFORMANCE_MONITOR_INFO);
321             Some(PerformanceMonitoringInfo {
322                 eax: res.eax,
323                 ebx: PerformanceMonitoringFeaturesEbx { bits: res.ebx },
324                 ecx: res.ecx,
325                 edx: res.edx,
326             })
327         } else {
328             None
329         }
330     }
331 
332     /// Information about topology (how many cores and what kind of cores).
get_extended_topology_info(&self) -> Option<ExtendedTopologyIter>333     pub fn get_extended_topology_info(&self) -> Option<ExtendedTopologyIter> {
334         if self.leaf_is_supported(EAX_EXTENDED_TOPOLOGY_INFO) {
335             Some(ExtendedTopologyIter { level: 0 })
336         } else {
337             None
338         }
339     }
340 
341     /// Information for saving/restoring extended register state.
get_extended_state_info(&self) -> Option<ExtendedStateInfo>342     pub fn get_extended_state_info(&self) -> Option<ExtendedStateInfo> {
343         if self.leaf_is_supported(EAX_EXTENDED_STATE_INFO) {
344             let res = cpuid!(EAX_EXTENDED_STATE_INFO, 0);
345             let res1 = cpuid!(EAX_EXTENDED_STATE_INFO, 1);
346             Some(ExtendedStateInfo {
347                 eax: ExtendedStateInfoXCR0Flags { bits: res.eax },
348                 ebx: res.ebx,
349                 ecx: res.ecx,
350                 edx: res.edx,
351                 eax1: res1.eax,
352                 ebx1: res1.ebx,
353                 ecx1: ExtendedStateInfoXSSFlags { bits: res1.ecx },
354                 edx1: res1.edx,
355             })
356         } else {
357             None
358         }
359     }
360 
361     /// Quality of service informations.
get_rdt_monitoring_info(&self) -> Option<RdtMonitoringInfo>362     pub fn get_rdt_monitoring_info(&self) -> Option<RdtMonitoringInfo> {
363         let res = cpuid!(EAX_RDT_MONITORING, 0);
364 
365         if self.leaf_is_supported(EAX_RDT_MONITORING) {
366             Some(RdtMonitoringInfo {
367                 ebx: res.ebx,
368                 edx: res.edx,
369             })
370         } else {
371             None
372         }
373     }
374 
375     /// Quality of service enforcement information.
get_rdt_allocation_info(&self) -> Option<RdtAllocationInfo>376     pub fn get_rdt_allocation_info(&self) -> Option<RdtAllocationInfo> {
377         let res = cpuid!(EAX_RDT_ALLOCATION, 0);
378 
379         if self.leaf_is_supported(EAX_RDT_ALLOCATION) {
380             Some(RdtAllocationInfo { ebx: res.ebx })
381         } else {
382             None
383         }
384     }
385 
get_sgx_info(&self) -> Option<SgxInfo>386     pub fn get_sgx_info(&self) -> Option<SgxInfo> {
387         // Leaf 12H sub-leaf 0 (ECX = 0) is supported if CPUID.(EAX=07H, ECX=0H):EBX[SGX] = 1.
388         self.get_extended_feature_info().and_then(|info| {
389             if self.leaf_is_supported(EAX_SGX) && info.has_sgx() {
390                 let res = cpuid!(EAX_SGX, 0);
391                 let res1 = cpuid!(EAX_SGX, 1);
392                 Some(SgxInfo {
393                     eax: res.eax,
394                     ebx: res.ebx,
395                     ecx: res.ecx,
396                     edx: res.edx,
397                     eax1: res1.eax,
398                     ebx1: res1.ebx,
399                     ecx1: res1.ecx,
400                     edx1: res1.edx,
401                 })
402             } else {
403                 None
404             }
405         })
406     }
407 
408     /// Intel Processor Trace Enumeration Information.
get_processor_trace_info(&self) -> Option<ProcessorTraceInfo>409     pub fn get_processor_trace_info(&self) -> Option<ProcessorTraceInfo> {
410         let res = cpuid!(EAX_TRACE_INFO, 0);
411         if self.leaf_is_supported(EAX_TRACE_INFO) {
412             let res1 = if res.eax >= 1 {
413                 Some(cpuid!(EAX_TRACE_INFO, 1))
414             } else {
415                 None
416             };
417 
418             Some(ProcessorTraceInfo {
419                 eax: res.eax,
420                 ebx: res.ebx,
421                 ecx: res.ecx,
422                 edx: res.edx,
423                 leaf1: res1,
424             })
425         } else {
426             None
427         }
428     }
429 
430     /// Time Stamp Counter/Core Crystal Clock Information.
get_tsc_info(&self) -> Option<TscInfo>431     pub fn get_tsc_info(&self) -> Option<TscInfo> {
432         let res = cpuid!(EAX_TIME_STAMP_COUNTER_INFO, 0);
433         if self.leaf_is_supported(EAX_TIME_STAMP_COUNTER_INFO) {
434             Some(TscInfo {
435                 eax: res.eax,
436                 ebx: res.ebx,
437                 ecx: res.ecx,
438             })
439         } else {
440             None
441         }
442     }
443 
444     /// Processor Frequency Information.
get_processor_frequency_info(&self) -> Option<ProcessorFrequencyInfo>445     pub fn get_processor_frequency_info(&self) -> Option<ProcessorFrequencyInfo> {
446         let res = cpuid!(EAX_FREQUENCY_INFO, 0);
447         if self.leaf_is_supported(EAX_FREQUENCY_INFO) {
448             Some(ProcessorFrequencyInfo {
449                 eax: res.eax,
450                 ebx: res.ebx,
451                 ecx: res.ecx,
452             })
453         } else {
454             None
455         }
456     }
457 
deterministic_address_translation_info(&self) -> Option<DatIter>458     pub fn deterministic_address_translation_info(&self) -> Option<DatIter> {
459         if self.leaf_is_supported(EAX_DETERMINISTIC_ADDRESS_TRANSLATION_INFO) {
460             let res = cpuid!(EAX_DETERMINISTIC_ADDRESS_TRANSLATION_INFO, 0);
461             Some(DatIter {
462                 current: 0,
463                 count: res.eax,
464             })
465         } else {
466             None
467         }
468     }
469 
get_soc_vendor_info(&self) -> Option<SoCVendorInfo>470     pub fn get_soc_vendor_info(&self) -> Option<SoCVendorInfo> {
471         let res = cpuid!(EAX_SOC_VENDOR_INFO, 0);
472         if self.leaf_is_supported(EAX_SOC_VENDOR_INFO) {
473             Some(SoCVendorInfo {
474                 eax: res.eax,
475                 ebx: res.ebx,
476                 ecx: res.ecx,
477                 edx: res.edx,
478             })
479         } else {
480             None
481         }
482     }
483 
get_hypervisor_info(&self) -> Option<HypervisorInfo>484     pub fn get_hypervisor_info(&self) -> Option<HypervisorInfo> {
485         let res = cpuid!(EAX_HYPERVISOR_INFO);
486         if res.eax > 0 {
487             Some(HypervisorInfo { res: res })
488         } else {
489             None
490         }
491     }
492 
493     /// Extended functionality of CPU described here (including more supported features).
494     /// This also contains a more detailed CPU model identifier.
get_extended_function_info(&self) -> Option<ExtendedFunctionInfo>495     pub fn get_extended_function_info(&self) -> Option<ExtendedFunctionInfo> {
496         let res = cpuid!(EAX_EXTENDED_FUNCTION_INFO);
497 
498         if res.eax == 0 {
499             return None;
500         }
501 
502         let mut ef = ExtendedFunctionInfo {
503             max_eax_value: res.eax - EAX_EXTENDED_FUNCTION_INFO,
504             data: [
505                 CpuIdResult {
506                     eax: res.eax,
507                     ebx: res.ebx,
508                     ecx: res.ecx,
509                     edx: res.edx,
510                 },
511                 CpuIdResult {
512                     eax: 0,
513                     ebx: 0,
514                     ecx: 0,
515                     edx: 0,
516                 },
517                 CpuIdResult {
518                     eax: 0,
519                     ebx: 0,
520                     ecx: 0,
521                     edx: 0,
522                 },
523                 CpuIdResult {
524                     eax: 0,
525                     ebx: 0,
526                     ecx: 0,
527                     edx: 0,
528                 },
529                 CpuIdResult {
530                     eax: 0,
531                     ebx: 0,
532                     ecx: 0,
533                     edx: 0,
534                 },
535                 CpuIdResult {
536                     eax: 0,
537                     ebx: 0,
538                     ecx: 0,
539                     edx: 0,
540                 },
541                 CpuIdResult {
542                     eax: 0,
543                     ebx: 0,
544                     ecx: 0,
545                     edx: 0,
546                 },
547                 CpuIdResult {
548                     eax: 0,
549                     ebx: 0,
550                     ecx: 0,
551                     edx: 0,
552                 },
553                 CpuIdResult {
554                     eax: 0,
555                     ebx: 0,
556                     ecx: 0,
557                     edx: 0,
558                 },
559             ],
560         };
561 
562         let max_eax_value = min(ef.max_eax_value + 1, ef.data.len() as u32);
563         for i in 1..max_eax_value {
564             ef.data[i as usize] = cpuid!(EAX_EXTENDED_FUNCTION_INFO + i);
565         }
566 
567         Some(ef)
568     }
569 
get_memory_encryption_info(&self) -> Option<MemoryEncryptionInfo>570     pub fn get_memory_encryption_info(&self) -> Option<MemoryEncryptionInfo> {
571         let res = cpuid!(EAX_EXTENDED_FUNCTION_INFO);
572         if res.eax < EAX_MEMORY_ENCRYPTION_INFO {
573             return None;
574         }
575 
576         let res = cpuid!(EAX_MEMORY_ENCRYPTION_INFO);
577         Some(MemoryEncryptionInfo {
578             eax: MemoryEncryptionInfoEax { bits: res.eax },
579             ebx: res.ebx,
580             ecx: res.ecx,
581             edx: res.edx,
582         })
583     }
584 }
585 
586 #[derive(Debug, Default)]
587 #[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))]
588 pub struct VendorInfo {
589     ebx: u32,
590     edx: u32,
591     ecx: u32,
592 }
593 
594 impl VendorInfo {
595     /// Return vendor identification as human readable string.
as_string<'a>(&'a self) -> &'a str596     pub fn as_string<'a>(&'a self) -> &'a str {
597         unsafe {
598             let brand_string_start = self as *const VendorInfo as *const u8;
599             let slice = slice::from_raw_parts(brand_string_start, 3 * 4);
600             let byte_array: &'a [u8] = transmute(slice);
601             str::from_utf8_unchecked(byte_array)
602         }
603     }
604 }
605 
606 /// Used to iterate over cache information contained in cpuid instruction.
607 #[derive(Debug, Default)]
608 #[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))]
609 pub struct CacheInfoIter {
610     current: u32,
611     eax: u32,
612     ebx: u32,
613     ecx: u32,
614     edx: u32,
615 }
616 
617 impl Iterator for CacheInfoIter {
618     type Item = CacheInfo;
619 
620     /// Iterate over all cache information.
next(&mut self) -> Option<CacheInfo>621     fn next(&mut self) -> Option<CacheInfo> {
622         // Every byte of the 4 register values returned by cpuid
623         // can contain information about a cache (except the
624         // very first one).
625         if self.current >= 4 * 4 {
626             return None;
627         }
628         let reg_index = self.current % 4;
629         let byte_index = self.current / 4;
630 
631         let reg = match reg_index {
632             0 => self.eax,
633             1 => self.ebx,
634             2 => self.ecx,
635             3 => self.edx,
636             _ => unreachable!(),
637         };
638 
639         let byte = as_bytes(&reg)[byte_index as usize];
640         if byte == 0 {
641             self.current += 1;
642             return self.next();
643         }
644 
645         for cache_info in CACHE_INFO_TABLE.iter() {
646             if cache_info.num == byte {
647                 self.current += 1;
648                 return Some(*cache_info);
649             }
650         }
651 
652         None
653     }
654 }
655 
656 /// What type of cache are we dealing with?
657 #[derive(Copy, Clone, Debug)]
658 #[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))]
659 pub enum CacheInfoType {
660     General,
661     Cache,
662     TLB,
663     STLB,
664     DTLB,
665     Prefetch,
666 }
667 
668 impl Default for CacheInfoType {
default() -> CacheInfoType669     fn default() -> CacheInfoType {
670         CacheInfoType::General
671     }
672 }
673 
674 /// Describes any kind of cache (TLB, Data and Instruction caches plus prefetchers).
675 #[derive(Copy, Clone, Debug, Default)]
676 #[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))]
677 pub struct CacheInfo {
678     /// Number as retrieved from cpuid
679     pub num: u8,
680     /// Cache type
681     pub typ: CacheInfoType,
682 }
683 
684 impl CacheInfo {
685     /// Description of the cache (from Intel Manual)
desc(&self) -> &'static str686     pub fn desc(&self) -> &'static str {
687         match self.num {
688             0x00 => "Null descriptor, this byte contains no information",
689             0x01 => "Instruction TLB: 4 KByte pages, 4-way set associative, 32 entries",
690             0x02 => "Instruction TLB: 4 MByte pages, fully associative, 2 entries",
691             0x03 => "Data TLB: 4 KByte pages, 4-way set associative, 64 entries",
692             0x04 => "Data TLB: 4 MByte pages, 4-way set associative, 8 entries",
693             0x05 => "Data TLB1: 4 MByte pages, 4-way set associative, 32 entries",
694             0x06 => "1st-level instruction cache: 8 KBytes, 4-way set associative, 32 byte line size",
695             0x08 => "1st-level instruction cache: 16 KBytes, 4-way set associative, 32 byte line size",
696             0x09 => "1st-level instruction cache: 32KBytes, 4-way set associative, 64 byte line size",
697             0x0A => "1st-level data cache: 8 KBytes, 2-way set associative, 32 byte line size",
698             0x0B => "Instruction TLB: 4 MByte pages, 4-way set associative, 4 entries",
699             0x0C => "1st-level data cache: 16 KBytes, 4-way set associative, 32 byte line size",
700             0x0D => "1st-level data cache: 16 KBytes, 4-way set associative, 64 byte line size",
701             0x0E => "1st-level data cache: 24 KBytes, 6-way set associative, 64 byte line size",
702             0x1D => "2nd-level cache: 128 KBytes, 2-way set associative, 64 byte line size",
703             0x21 => "2nd-level cache: 256 KBytes, 8-way set associative, 64 byte line size",
704             0x22 => "3rd-level cache: 512 KBytes, 4-way set associative, 64 byte line size, 2 lines per sector",
705             0x23 => "3rd-level cache: 1 MBytes, 8-way set associative, 64 byte line size, 2 lines per sector",
706             0x24 => "2nd-level cache: 1 MBytes, 16-way set associative, 64 byte line size",
707             0x25 => "3rd-level cache: 2 MBytes, 8-way set associative, 64 byte line size, 2 lines per sector",
708             0x29 => "3rd-level cache: 4 MBytes, 8-way set associative, 64 byte line size, 2 lines per sector",
709             0x2C => "1st-level data cache: 32 KBytes, 8-way set associative, 64 byte line size",
710             0x30 => "1st-level instruction cache: 32 KBytes, 8-way set associative, 64 byte line size",
711             0x40 => "No 2nd-level cache or, if processor contains a valid 2nd-level cache, no 3rd-level cache",
712             0x41 => "2nd-level cache: 128 KBytes, 4-way set associative, 32 byte line size",
713             0x42 => "2nd-level cache: 256 KBytes, 4-way set associative, 32 byte line size",
714             0x43 => "2nd-level cache: 512 KBytes, 4-way set associative, 32 byte line size",
715             0x44 => "2nd-level cache: 1 MByte, 4-way set associative, 32 byte line size",
716             0x45 => "2nd-level cache: 2 MByte, 4-way set associative, 32 byte line size",
717             0x46 => "3rd-level cache: 4 MByte, 4-way set associative, 64 byte line size",
718             0x47 => "3rd-level cache: 8 MByte, 8-way set associative, 64 byte line size",
719             0x48 => "2nd-level cache: 3MByte, 12-way set associative, 64 byte line size",
720             0x49 => "3rd-level cache: 4MB, 16-way set associative, 64-byte line size (Intel Xeon processor MP, Family 0FH, Model 06H); 2nd-level cache: 4 MByte, 16-way set ssociative, 64 byte line size",
721             0x4A => "3rd-level cache: 6MByte, 12-way set associative, 64 byte line size",
722             0x4B => "3rd-level cache: 8MByte, 16-way set associative, 64 byte line size",
723             0x4C => "3rd-level cache: 12MByte, 12-way set associative, 64 byte line size",
724             0x4D => "3rd-level cache: 16MByte, 16-way set associative, 64 byte line size",
725             0x4E => "2nd-level cache: 6MByte, 24-way set associative, 64 byte line size",
726             0x4F => "Instruction TLB: 4 KByte pages, 32 entries",
727             0x50 => "Instruction TLB: 4 KByte and 2-MByte or 4-MByte pages, 64 entries",
728             0x51 => "Instruction TLB: 4 KByte and 2-MByte or 4-MByte pages, 128 entries",
729             0x52 => "Instruction TLB: 4 KByte and 2-MByte or 4-MByte pages, 256 entries",
730             0x55 => "Instruction TLB: 2-MByte or 4-MByte pages, fully associative, 7 entries",
731             0x56 => "Data TLB0: 4 MByte pages, 4-way set associative, 16 entries",
732             0x57 => "Data TLB0: 4 KByte pages, 4-way associative, 16 entries",
733             0x59 => "Data TLB0: 4 KByte pages, fully associative, 16 entries",
734             0x5A => "Data TLB0: 2-MByte or 4 MByte pages, 4-way set associative, 32 entries",
735             0x5B => "Data TLB: 4 KByte and 4 MByte pages, 64 entries",
736             0x5C => "Data TLB: 4 KByte and 4 MByte pages,128 entries",
737             0x5D => "Data TLB: 4 KByte and 4 MByte pages,256 entries",
738             0x60 => "1st-level data cache: 16 KByte, 8-way set associative, 64 byte line size",
739             0x61 => "Instruction TLB: 4 KByte pages, fully associative, 48 entries",
740             0x63 => "Data TLB: 2 MByte or 4 MByte pages, 4-way set associative, 32 entries and a separate array with 1 GByte pages, 4-way set associative, 4 entries",
741             0x64 => "Data TLB: 4 KByte pages, 4-way set associative, 512 entries",
742             0x66 => "1st-level data cache: 8 KByte, 4-way set associative, 64 byte line size",
743             0x67 => "1st-level data cache: 16 KByte, 4-way set associative, 64 byte line size",
744             0x68 => "1st-level data cache: 32 KByte, 4-way set associative, 64 byte line size",
745             0x6A => "uTLB: 4 KByte pages, 8-way set associative, 64 entries",
746             0x6B => "DTLB: 4 KByte pages, 8-way set associative, 256 entries",
747             0x6C => "DTLB: 2M/4M pages, 8-way set associative, 128 entries",
748             0x6D => "DTLB: 1 GByte pages, fully associative, 16 entries",
749             0x70 => "Trace cache: 12 K-μop, 8-way set associative",
750             0x71 => "Trace cache: 16 K-μop, 8-way set associative",
751             0x72 => "Trace cache: 32 K-μop, 8-way set associative",
752             0x76 => "Instruction TLB: 2M/4M pages, fully associative, 8 entries",
753             0x78 => "2nd-level cache: 1 MByte, 4-way set associative, 64byte line size",
754             0x79 => "2nd-level cache: 128 KByte, 8-way set associative, 64 byte line size, 2 lines per sector",
755             0x7A => "2nd-level cache: 256 KByte, 8-way set associative, 64 byte line size, 2 lines per sector",
756             0x7B => "2nd-level cache: 512 KByte, 8-way set associative, 64 byte line size, 2 lines per sector",
757             0x7C => "2nd-level cache: 1 MByte, 8-way set associative, 64 byte line size, 2 lines per sector",
758             0x7D => "2nd-level cache: 2 MByte, 8-way set associative, 64byte line size",
759             0x7F => "2nd-level cache: 512 KByte, 2-way set associative, 64-byte line size",
760             0x80 => "2nd-level cache: 512 KByte, 8-way set associative, 64-byte line size",
761             0x82 => "2nd-level cache: 256 KByte, 8-way set associative, 32 byte line size",
762             0x83 => "2nd-level cache: 512 KByte, 8-way set associative, 32 byte line size",
763             0x84 => "2nd-level cache: 1 MByte, 8-way set associative, 32 byte line size",
764             0x85 => "2nd-level cache: 2 MByte, 8-way set associative, 32 byte line size",
765             0x86 => "2nd-level cache: 512 KByte, 4-way set associative, 64 byte line size",
766             0x87 => "2nd-level cache: 1 MByte, 8-way set associative, 64 byte line size",
767             0xA0 => "DTLB: 4k pages, fully associative, 32 entries",
768             0xB0 => "Instruction TLB: 4 KByte pages, 4-way set associative, 128 entries",
769             0xB1 => "Instruction TLB: 2M pages, 4-way, 8 entries or 4M pages, 4-way, 4 entries",
770             0xB2 => "Instruction TLB: 4KByte pages, 4-way set associative, 64 entries",
771             0xB3 => "Data TLB: 4 KByte pages, 4-way set associative, 128 entries",
772             0xB4 => "Data TLB1: 4 KByte pages, 4-way associative, 256 entries",
773             0xB5 => "Instruction TLB: 4KByte pages, 8-way set associative, 64 entries",
774             0xB6 => "Instruction TLB: 4KByte pages, 8-way set associative, 128 entries",
775             0xBA => "Data TLB1: 4 KByte pages, 4-way associative, 64 entries",
776             0xC0 => "Data TLB: 4 KByte and 4 MByte pages, 4-way associative, 8 entries",
777             0xC1 => "Shared 2nd-Level TLB: 4 KByte/2MByte pages, 8-way associative, 1024 entries",
778             0xC2 => "DTLB: 2 MByte/$MByte pages, 4-way associative, 16 entries",
779             0xC3 => "Shared 2nd-Level TLB: 4 KByte /2 MByte pages, 6-way associative, 1536 entries. Also 1GBbyte pages, 4-way, 16 entries.",
780             0xC4 => "DTLB: 2M/4M Byte pages, 4-way associative, 32 entries",
781             0xCA => "Shared 2nd-Level TLB: 4 KByte pages, 4-way associative, 512 entries",
782             0xD0 => "3rd-level cache: 512 KByte, 4-way set associative, 64 byte line size",
783             0xD1 => "3rd-level cache: 1 MByte, 4-way set associative, 64 byte line size",
784             0xD2 => "3rd-level cache: 2 MByte, 4-way set associative, 64 byte line size",
785             0xD6 => "3rd-level cache: 1 MByte, 8-way set associative, 64 byte line size",
786             0xD7 => "3rd-level cache: 2 MByte, 8-way set associative, 64 byte line size",
787             0xD8 => "3rd-level cache: 4 MByte, 8-way set associative, 64 byte line size",
788             0xDC => "3rd-level cache: 1.5 MByte, 12-way set associative, 64 byte line size",
789             0xDD => "3rd-level cache: 3 MByte, 12-way set associative, 64 byte line size",
790             0xDE => "3rd-level cache: 6 MByte, 12-way set associative, 64 byte line size",
791             0xE2 => "3rd-level cache: 2 MByte, 16-way set associative, 64 byte line size",
792             0xE3 => "3rd-level cache: 4 MByte, 16-way set associative, 64 byte line size",
793             0xE4 => "3rd-level cache: 8 MByte, 16-way set associative, 64 byte line size",
794             0xEA => "3rd-level cache: 12MByte, 24-way set associative, 64 byte line size",
795             0xEB => "3rd-level cache: 18MByte, 24-way set associative, 64 byte line size",
796             0xEC => "3rd-level cache: 24MByte, 24-way set associative, 64 byte line size",
797             0xF0 => "64-Byte prefetching",
798             0xF1 => "128-Byte prefetching",
799             0xFE => "CPUID leaf 2 does not report TLB descriptor information; use CPUID leaf 18H to query TLB and other address translation parameters.",
800             0xFF => "CPUID leaf 2 does not report cache descriptor information, use CPUID leaf 4 to query cache parameters",
801             _ => "Unknown cache type!"
802         }
803     }
804 }
805 
806 impl fmt::Display for CacheInfo {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result807     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
808         let typ = match self.typ {
809             CacheInfoType::General => "N/A",
810             CacheInfoType::Cache => "Cache",
811             CacheInfoType::TLB => "TLB",
812             CacheInfoType::STLB => "STLB",
813             CacheInfoType::DTLB => "DTLB",
814             CacheInfoType::Prefetch => "Prefetcher",
815         };
816 
817         write!(f, "{:x}:\t {}: {}", self.num, typ, self.desc())
818     }
819 }
820 
821 /// This table is taken from Intel manual (Section CPUID instruction).
822 pub const CACHE_INFO_TABLE: [CacheInfo; 108] = [
823     CacheInfo {
824         num: 0x00,
825         typ: CacheInfoType::General,
826     },
827     CacheInfo {
828         num: 0x01,
829         typ: CacheInfoType::TLB,
830     },
831     CacheInfo {
832         num: 0x02,
833         typ: CacheInfoType::TLB,
834     },
835     CacheInfo {
836         num: 0x03,
837         typ: CacheInfoType::TLB,
838     },
839     CacheInfo {
840         num: 0x04,
841         typ: CacheInfoType::TLB,
842     },
843     CacheInfo {
844         num: 0x05,
845         typ: CacheInfoType::TLB,
846     },
847     CacheInfo {
848         num: 0x06,
849         typ: CacheInfoType::Cache,
850     },
851     CacheInfo {
852         num: 0x08,
853         typ: CacheInfoType::Cache,
854     },
855     CacheInfo {
856         num: 0x09,
857         typ: CacheInfoType::Cache,
858     },
859     CacheInfo {
860         num: 0x0A,
861         typ: CacheInfoType::Cache,
862     },
863     CacheInfo {
864         num: 0x0B,
865         typ: CacheInfoType::TLB,
866     },
867     CacheInfo {
868         num: 0x0C,
869         typ: CacheInfoType::Cache,
870     },
871     CacheInfo {
872         num: 0x0D,
873         typ: CacheInfoType::Cache,
874     },
875     CacheInfo {
876         num: 0x0E,
877         typ: CacheInfoType::Cache,
878     },
879     CacheInfo {
880         num: 0x21,
881         typ: CacheInfoType::Cache,
882     },
883     CacheInfo {
884         num: 0x22,
885         typ: CacheInfoType::Cache,
886     },
887     CacheInfo {
888         num: 0x23,
889         typ: CacheInfoType::Cache,
890     },
891     CacheInfo {
892         num: 0x24,
893         typ: CacheInfoType::Cache,
894     },
895     CacheInfo {
896         num: 0x25,
897         typ: CacheInfoType::Cache,
898     },
899     CacheInfo {
900         num: 0x29,
901         typ: CacheInfoType::Cache,
902     },
903     CacheInfo {
904         num: 0x2C,
905         typ: CacheInfoType::Cache,
906     },
907     CacheInfo {
908         num: 0x30,
909         typ: CacheInfoType::Cache,
910     },
911     CacheInfo {
912         num: 0x40,
913         typ: CacheInfoType::Cache,
914     },
915     CacheInfo {
916         num: 0x41,
917         typ: CacheInfoType::Cache,
918     },
919     CacheInfo {
920         num: 0x42,
921         typ: CacheInfoType::Cache,
922     },
923     CacheInfo {
924         num: 0x43,
925         typ: CacheInfoType::Cache,
926     },
927     CacheInfo {
928         num: 0x44,
929         typ: CacheInfoType::Cache,
930     },
931     CacheInfo {
932         num: 0x45,
933         typ: CacheInfoType::Cache,
934     },
935     CacheInfo {
936         num: 0x46,
937         typ: CacheInfoType::Cache,
938     },
939     CacheInfo {
940         num: 0x47,
941         typ: CacheInfoType::Cache,
942     },
943     CacheInfo {
944         num: 0x48,
945         typ: CacheInfoType::Cache,
946     },
947     CacheInfo {
948         num: 0x49,
949         typ: CacheInfoType::Cache,
950     },
951     CacheInfo {
952         num: 0x4A,
953         typ: CacheInfoType::Cache,
954     },
955     CacheInfo {
956         num: 0x4B,
957         typ: CacheInfoType::Cache,
958     },
959     CacheInfo {
960         num: 0x4C,
961         typ: CacheInfoType::Cache,
962     },
963     CacheInfo {
964         num: 0x4D,
965         typ: CacheInfoType::Cache,
966     },
967     CacheInfo {
968         num: 0x4E,
969         typ: CacheInfoType::Cache,
970     },
971     CacheInfo {
972         num: 0x4F,
973         typ: CacheInfoType::TLB,
974     },
975     CacheInfo {
976         num: 0x50,
977         typ: CacheInfoType::TLB,
978     },
979     CacheInfo {
980         num: 0x51,
981         typ: CacheInfoType::TLB,
982     },
983     CacheInfo {
984         num: 0x52,
985         typ: CacheInfoType::TLB,
986     },
987     CacheInfo {
988         num: 0x55,
989         typ: CacheInfoType::TLB,
990     },
991     CacheInfo {
992         num: 0x56,
993         typ: CacheInfoType::TLB,
994     },
995     CacheInfo {
996         num: 0x57,
997         typ: CacheInfoType::TLB,
998     },
999     CacheInfo {
1000         num: 0x59,
1001         typ: CacheInfoType::TLB,
1002     },
1003     CacheInfo {
1004         num: 0x5A,
1005         typ: CacheInfoType::TLB,
1006     },
1007     CacheInfo {
1008         num: 0x5B,
1009         typ: CacheInfoType::TLB,
1010     },
1011     CacheInfo {
1012         num: 0x5C,
1013         typ: CacheInfoType::TLB,
1014     },
1015     CacheInfo {
1016         num: 0x5D,
1017         typ: CacheInfoType::TLB,
1018     },
1019     CacheInfo {
1020         num: 0x60,
1021         typ: CacheInfoType::Cache,
1022     },
1023     CacheInfo {
1024         num: 0x61,
1025         typ: CacheInfoType::TLB,
1026     },
1027     CacheInfo {
1028         num: 0x63,
1029         typ: CacheInfoType::TLB,
1030     },
1031     CacheInfo {
1032         num: 0x66,
1033         typ: CacheInfoType::Cache,
1034     },
1035     CacheInfo {
1036         num: 0x67,
1037         typ: CacheInfoType::Cache,
1038     },
1039     CacheInfo {
1040         num: 0x68,
1041         typ: CacheInfoType::Cache,
1042     },
1043     CacheInfo {
1044         num: 0x6A,
1045         typ: CacheInfoType::Cache,
1046     },
1047     CacheInfo {
1048         num: 0x6B,
1049         typ: CacheInfoType::Cache,
1050     },
1051     CacheInfo {
1052         num: 0x6C,
1053         typ: CacheInfoType::Cache,
1054     },
1055     CacheInfo {
1056         num: 0x6D,
1057         typ: CacheInfoType::Cache,
1058     },
1059     CacheInfo {
1060         num: 0x70,
1061         typ: CacheInfoType::Cache,
1062     },
1063     CacheInfo {
1064         num: 0x71,
1065         typ: CacheInfoType::Cache,
1066     },
1067     CacheInfo {
1068         num: 0x72,
1069         typ: CacheInfoType::Cache,
1070     },
1071     CacheInfo {
1072         num: 0x76,
1073         typ: CacheInfoType::TLB,
1074     },
1075     CacheInfo {
1076         num: 0x78,
1077         typ: CacheInfoType::Cache,
1078     },
1079     CacheInfo {
1080         num: 0x79,
1081         typ: CacheInfoType::Cache,
1082     },
1083     CacheInfo {
1084         num: 0x7A,
1085         typ: CacheInfoType::Cache,
1086     },
1087     CacheInfo {
1088         num: 0x7B,
1089         typ: CacheInfoType::Cache,
1090     },
1091     CacheInfo {
1092         num: 0x7C,
1093         typ: CacheInfoType::Cache,
1094     },
1095     CacheInfo {
1096         num: 0x7D,
1097         typ: CacheInfoType::Cache,
1098     },
1099     CacheInfo {
1100         num: 0x7F,
1101         typ: CacheInfoType::Cache,
1102     },
1103     CacheInfo {
1104         num: 0x80,
1105         typ: CacheInfoType::Cache,
1106     },
1107     CacheInfo {
1108         num: 0x82,
1109         typ: CacheInfoType::Cache,
1110     },
1111     CacheInfo {
1112         num: 0x83,
1113         typ: CacheInfoType::Cache,
1114     },
1115     CacheInfo {
1116         num: 0x84,
1117         typ: CacheInfoType::Cache,
1118     },
1119     CacheInfo {
1120         num: 0x85,
1121         typ: CacheInfoType::Cache,
1122     },
1123     CacheInfo {
1124         num: 0x86,
1125         typ: CacheInfoType::Cache,
1126     },
1127     CacheInfo {
1128         num: 0x87,
1129         typ: CacheInfoType::Cache,
1130     },
1131     CacheInfo {
1132         num: 0xB0,
1133         typ: CacheInfoType::TLB,
1134     },
1135     CacheInfo {
1136         num: 0xB1,
1137         typ: CacheInfoType::TLB,
1138     },
1139     CacheInfo {
1140         num: 0xB2,
1141         typ: CacheInfoType::TLB,
1142     },
1143     CacheInfo {
1144         num: 0xB3,
1145         typ: CacheInfoType::TLB,
1146     },
1147     CacheInfo {
1148         num: 0xB4,
1149         typ: CacheInfoType::TLB,
1150     },
1151     CacheInfo {
1152         num: 0xB5,
1153         typ: CacheInfoType::TLB,
1154     },
1155     CacheInfo {
1156         num: 0xB6,
1157         typ: CacheInfoType::TLB,
1158     },
1159     CacheInfo {
1160         num: 0xBA,
1161         typ: CacheInfoType::TLB,
1162     },
1163     CacheInfo {
1164         num: 0xC0,
1165         typ: CacheInfoType::TLB,
1166     },
1167     CacheInfo {
1168         num: 0xC1,
1169         typ: CacheInfoType::STLB,
1170     },
1171     CacheInfo {
1172         num: 0xC2,
1173         typ: CacheInfoType::DTLB,
1174     },
1175     CacheInfo {
1176         num: 0xCA,
1177         typ: CacheInfoType::STLB,
1178     },
1179     CacheInfo {
1180         num: 0xD0,
1181         typ: CacheInfoType::Cache,
1182     },
1183     CacheInfo {
1184         num: 0xD1,
1185         typ: CacheInfoType::Cache,
1186     },
1187     CacheInfo {
1188         num: 0xD2,
1189         typ: CacheInfoType::Cache,
1190     },
1191     CacheInfo {
1192         num: 0xD6,
1193         typ: CacheInfoType::Cache,
1194     },
1195     CacheInfo {
1196         num: 0xD7,
1197         typ: CacheInfoType::Cache,
1198     },
1199     CacheInfo {
1200         num: 0xD8,
1201         typ: CacheInfoType::Cache,
1202     },
1203     CacheInfo {
1204         num: 0xDC,
1205         typ: CacheInfoType::Cache,
1206     },
1207     CacheInfo {
1208         num: 0xDD,
1209         typ: CacheInfoType::Cache,
1210     },
1211     CacheInfo {
1212         num: 0xDE,
1213         typ: CacheInfoType::Cache,
1214     },
1215     CacheInfo {
1216         num: 0xE2,
1217         typ: CacheInfoType::Cache,
1218     },
1219     CacheInfo {
1220         num: 0xE3,
1221         typ: CacheInfoType::Cache,
1222     },
1223     CacheInfo {
1224         num: 0xE4,
1225         typ: CacheInfoType::Cache,
1226     },
1227     CacheInfo {
1228         num: 0xEA,
1229         typ: CacheInfoType::Cache,
1230     },
1231     CacheInfo {
1232         num: 0xEB,
1233         typ: CacheInfoType::Cache,
1234     },
1235     CacheInfo {
1236         num: 0xEC,
1237         typ: CacheInfoType::Cache,
1238     },
1239     CacheInfo {
1240         num: 0xF0,
1241         typ: CacheInfoType::Prefetch,
1242     },
1243     CacheInfo {
1244         num: 0xF1,
1245         typ: CacheInfoType::Prefetch,
1246     },
1247     CacheInfo {
1248         num: 0xFE,
1249         typ: CacheInfoType::General,
1250     },
1251     CacheInfo {
1252         num: 0xFF,
1253         typ: CacheInfoType::General,
1254     },
1255 ];
1256 
1257 impl fmt::Display for VendorInfo {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result1258     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1259         write!(f, "{}", self.as_string())
1260     }
1261 }
1262 
1263 #[derive(Debug, Default)]
1264 #[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))]
1265 pub struct ProcessorSerial {
1266     ecx: u32,
1267     edx: u32,
1268 }
1269 
1270 impl ProcessorSerial {
1271     /// Bits 00-31 of 96 bit processor serial number.
1272     /// (Available in Pentium III processor only; otherwise, the value in this register is reserved.)
serial_lower(&self) -> u321273     pub fn serial_lower(&self) -> u32 {
1274         self.ecx
1275     }
1276 
1277     /// Bits 32-63 of 96 bit processor serial number.
1278     /// (Available in Pentium III processor only; otherwise, the value in this register is reserved.)
serial_middle(&self) -> u321279     pub fn serial_middle(&self) -> u32 {
1280         self.edx
1281     }
1282 }
1283 
1284 #[derive(Debug, Default)]
1285 #[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))]
1286 pub struct FeatureInfo {
1287     eax: u32,
1288     ebx: u32,
1289     edx_ecx: FeatureInfoFlags,
1290 }
1291 
1292 impl FeatureInfo {
1293     /// Version Information: Extended Family
extended_family_id(&self) -> u81294     pub fn extended_family_id(&self) -> u8 {
1295         get_bits(self.eax, 20, 27) as u8
1296     }
1297 
1298     /// Version Information: Extended Model
extended_model_id(&self) -> u81299     pub fn extended_model_id(&self) -> u8 {
1300         get_bits(self.eax, 16, 19) as u8
1301     }
1302 
1303     /// Version Information: Family
family_id(&self) -> u81304     pub fn family_id(&self) -> u8 {
1305         get_bits(self.eax, 8, 11) as u8
1306     }
1307 
1308     /// Version Information: Model
model_id(&self) -> u81309     pub fn model_id(&self) -> u8 {
1310         get_bits(self.eax, 4, 7) as u8
1311     }
1312 
1313     /// Version Information: Stepping ID
stepping_id(&self) -> u81314     pub fn stepping_id(&self) -> u8 {
1315         get_bits(self.eax, 0, 3) as u8
1316     }
1317 
1318     /// Brand Index
brand_index(&self) -> u81319     pub fn brand_index(&self) -> u8 {
1320         get_bits(self.ebx, 0, 7) as u8
1321     }
1322 
1323     /// CLFLUSH line size (Value ∗ 8 = cache line size in bytes)
cflush_cache_line_size(&self) -> u81324     pub fn cflush_cache_line_size(&self) -> u8 {
1325         get_bits(self.ebx, 8, 15) as u8
1326     }
1327 
1328     /// Initial APIC ID
initial_local_apic_id(&self) -> u81329     pub fn initial_local_apic_id(&self) -> u8 {
1330         get_bits(self.ebx, 24, 31) as u8
1331     }
1332 
1333     /// Maximum number of addressable IDs for logical processors in this physical package.
max_logical_processor_ids(&self) -> u81334     pub fn max_logical_processor_ids(&self) -> u8 {
1335         get_bits(self.ebx, 16, 23) as u8
1336     }
1337 
1338     check_flag!(
1339         doc = "Streaming SIMD Extensions 3 (SSE3). A value of 1 indicates the processor \
1340                supports this technology.",
1341         has_sse3,
1342         edx_ecx,
1343         FeatureInfoFlags::SSE3
1344     );
1345 
1346     check_flag!(
1347         doc = "PCLMULQDQ. A value of 1 indicates the processor supports the PCLMULQDQ \
1348                instruction",
1349         has_pclmulqdq,
1350         edx_ecx,
1351         FeatureInfoFlags::PCLMULQDQ
1352     );
1353 
1354     check_flag!(
1355         doc = "64-bit DS Area. A value of 1 indicates the processor supports DS area \
1356                using 64-bit layout",
1357         has_ds_area,
1358         edx_ecx,
1359         FeatureInfoFlags::DTES64
1360     );
1361 
1362     check_flag!(
1363         doc = "MONITOR/MWAIT. A value of 1 indicates the processor supports this feature.",
1364         has_monitor_mwait,
1365         edx_ecx,
1366         FeatureInfoFlags::MONITOR
1367     );
1368 
1369     check_flag!(
1370         doc = "CPL Qualified Debug Store. A value of 1 indicates the processor supports \
1371                the extensions to the  Debug Store feature to allow for branch message \
1372                storage qualified by CPL.",
1373         has_cpl,
1374         edx_ecx,
1375         FeatureInfoFlags::DSCPL
1376     );
1377 
1378     check_flag!(
1379         doc = "Virtual Machine Extensions. A value of 1 indicates that the processor \
1380                supports this technology.",
1381         has_vmx,
1382         edx_ecx,
1383         FeatureInfoFlags::VMX
1384     );
1385 
1386     check_flag!(
1387         doc = "Safer Mode Extensions. A value of 1 indicates that the processor supports \
1388                this technology. See Chapter 5, Safer Mode Extensions Reference.",
1389         has_smx,
1390         edx_ecx,
1391         FeatureInfoFlags::SMX
1392     );
1393 
1394     check_flag!(
1395         doc = "Enhanced Intel SpeedStep® technology. A value of 1 indicates that the \
1396                processor supports this technology.",
1397         has_eist,
1398         edx_ecx,
1399         FeatureInfoFlags::EIST
1400     );
1401 
1402     check_flag!(
1403         doc = "Thermal Monitor 2. A value of 1 indicates whether the processor supports \
1404                this technology.",
1405         has_tm2,
1406         edx_ecx,
1407         FeatureInfoFlags::TM2
1408     );
1409 
1410     check_flag!(
1411         doc = "A value of 1 indicates the presence of the Supplemental Streaming SIMD \
1412                Extensions 3 (SSSE3). A value of 0 indicates the instruction extensions \
1413                are not present in the processor",
1414         has_ssse3,
1415         edx_ecx,
1416         FeatureInfoFlags::SSSE3
1417     );
1418 
1419     check_flag!(
1420         doc = "L1 Context ID. A value of 1 indicates the L1 data cache mode can be set \
1421                to either adaptive mode or shared mode. A value of 0 indicates this \
1422                feature is not supported. See definition of the IA32_MISC_ENABLE MSR Bit \
1423                24 (L1 Data Cache Context Mode) for details.",
1424         has_cnxtid,
1425         edx_ecx,
1426         FeatureInfoFlags::CNXTID
1427     );
1428 
1429     check_flag!(
1430         doc = "A value of 1 indicates the processor supports FMA extensions using YMM \
1431                state.",
1432         has_fma,
1433         edx_ecx,
1434         FeatureInfoFlags::FMA
1435     );
1436 
1437     check_flag!(
1438         doc = "CMPXCHG16B Available. A value of 1 indicates that the feature is \
1439                available. See the CMPXCHG8B/CMPXCHG16B Compare and Exchange Bytes \
1440                section. 14",
1441         has_cmpxchg16b,
1442         edx_ecx,
1443         FeatureInfoFlags::CMPXCHG16B
1444     );
1445 
1446     check_flag!(
1447         doc = "Perfmon and Debug Capability: A value of 1 indicates the processor \
1448                supports the performance   and debug feature indication MSR \
1449                IA32_PERF_CAPABILITIES.",
1450         has_pdcm,
1451         edx_ecx,
1452         FeatureInfoFlags::PDCM
1453     );
1454 
1455     check_flag!(
1456         doc = "Process-context identifiers. A value of 1 indicates that the processor \
1457                supports PCIDs and the software may set CR4.PCIDE to 1.",
1458         has_pcid,
1459         edx_ecx,
1460         FeatureInfoFlags::PCID
1461     );
1462 
1463     check_flag!(
1464         doc = "A value of 1 indicates the processor supports the ability to prefetch \
1465                data from a memory mapped device.",
1466         has_dca,
1467         edx_ecx,
1468         FeatureInfoFlags::DCA
1469     );
1470 
1471     check_flag!(
1472         doc = "A value of 1 indicates that the processor supports SSE4.1.",
1473         has_sse41,
1474         edx_ecx,
1475         FeatureInfoFlags::SSE41
1476     );
1477 
1478     check_flag!(
1479         doc = "A value of 1 indicates that the processor supports SSE4.2.",
1480         has_sse42,
1481         edx_ecx,
1482         FeatureInfoFlags::SSE42
1483     );
1484 
1485     check_flag!(
1486         doc = "A value of 1 indicates that the processor supports x2APIC feature.",
1487         has_x2apic,
1488         edx_ecx,
1489         FeatureInfoFlags::X2APIC
1490     );
1491 
1492     check_flag!(
1493         doc = "A value of 1 indicates that the processor supports MOVBE instruction.",
1494         has_movbe,
1495         edx_ecx,
1496         FeatureInfoFlags::MOVBE
1497     );
1498 
1499     check_flag!(
1500         doc = "A value of 1 indicates that the processor supports the POPCNT instruction.",
1501         has_popcnt,
1502         edx_ecx,
1503         FeatureInfoFlags::POPCNT
1504     );
1505 
1506     check_flag!(
1507         doc = "A value of 1 indicates that the processors local APIC timer supports \
1508                one-shot operation using a TSC deadline value.",
1509         has_tsc_deadline,
1510         edx_ecx,
1511         FeatureInfoFlags::TSC_DEADLINE
1512     );
1513 
1514     check_flag!(
1515         doc = "A value of 1 indicates that the processor supports the AESNI instruction \
1516                extensions.",
1517         has_aesni,
1518         edx_ecx,
1519         FeatureInfoFlags::AESNI
1520     );
1521 
1522     check_flag!(
1523         doc = "A value of 1 indicates that the processor supports the XSAVE/XRSTOR \
1524                processor extended states feature, the XSETBV/XGETBV instructions, and \
1525                XCR0.",
1526         has_xsave,
1527         edx_ecx,
1528         FeatureInfoFlags::XSAVE
1529     );
1530 
1531     check_flag!(
1532         doc = "A value of 1 indicates that the OS has enabled XSETBV/XGETBV instructions \
1533                to access XCR0, and support for processor extended state management using \
1534                XSAVE/XRSTOR.",
1535         has_oxsave,
1536         edx_ecx,
1537         FeatureInfoFlags::OSXSAVE
1538     );
1539 
1540     check_flag!(
1541         doc = "A value of 1 indicates the processor supports the AVX instruction \
1542                extensions.",
1543         has_avx,
1544         edx_ecx,
1545         FeatureInfoFlags::AVX
1546     );
1547 
1548     check_flag!(
1549         doc = "A value of 1 indicates that processor supports 16-bit floating-point \
1550                conversion instructions.",
1551         has_f16c,
1552         edx_ecx,
1553         FeatureInfoFlags::F16C
1554     );
1555 
1556     check_flag!(
1557         doc = "A value of 1 indicates that processor supports RDRAND instruction.",
1558         has_rdrand,
1559         edx_ecx,
1560         FeatureInfoFlags::RDRAND
1561     );
1562 
1563     check_flag!(
1564         doc = "Floating Point Unit On-Chip. The processor contains an x87 FPU.",
1565         has_fpu,
1566         edx_ecx,
1567         FeatureInfoFlags::FPU
1568     );
1569 
1570     check_flag!(
1571         doc = "Virtual 8086 Mode Enhancements. Virtual 8086 mode enhancements, including \
1572                CR4.VME for controlling the feature, CR4.PVI for protected mode virtual \
1573                interrupts, software interrupt indirection, expansion of the TSS with the \
1574                software indirection bitmap, and EFLAGS.VIF and EFLAGS.VIP flags.",
1575         has_vme,
1576         edx_ecx,
1577         FeatureInfoFlags::VME
1578     );
1579 
1580     check_flag!(
1581         doc = "Debugging Extensions. Support for I/O breakpoints, including CR4.DE for \
1582                controlling the feature, and optional trapping of accesses to DR4 and DR5.",
1583         has_de,
1584         edx_ecx,
1585         FeatureInfoFlags::DE
1586     );
1587 
1588     check_flag!(
1589         doc = "Page Size Extension. Large pages of size 4 MByte are supported, including \
1590                CR4.PSE for controlling the feature, the defined dirty bit in PDE (Page \
1591                Directory Entries), optional reserved bit trapping in CR3, PDEs, and PTEs.",
1592         has_pse,
1593         edx_ecx,
1594         FeatureInfoFlags::PSE
1595     );
1596 
1597     check_flag!(
1598         doc = "Time Stamp Counter. The RDTSC instruction is supported, including CR4.TSD \
1599                for controlling privilege.",
1600         has_tsc,
1601         edx_ecx,
1602         FeatureInfoFlags::TSC
1603     );
1604 
1605     check_flag!(
1606         doc = "Model Specific Registers RDMSR and WRMSR Instructions. The RDMSR and \
1607                WRMSR instructions are supported. Some of the MSRs are implementation \
1608                dependent.",
1609         has_msr,
1610         edx_ecx,
1611         FeatureInfoFlags::MSR
1612     );
1613 
1614     check_flag!(
1615         doc = "Physical Address Extension. Physical addresses greater than 32 bits are \
1616                supported: extended page table entry formats, an extra level in the page \
1617                translation tables is defined, 2-MByte pages are supported instead of 4 \
1618                Mbyte pages if PAE bit is 1.",
1619         has_pae,
1620         edx_ecx,
1621         FeatureInfoFlags::PAE
1622     );
1623 
1624     check_flag!(
1625         doc = "Machine Check Exception. Exception 18 is defined for Machine Checks, \
1626                including CR4.MCE for controlling the feature. This feature does not \
1627                define the model-specific implementations of machine-check error logging, \
1628                reporting, and processor shutdowns. Machine Check exception handlers may \
1629                have to depend on processor version to do model specific processing of \
1630                the exception, or test for the presence of the Machine Check feature.",
1631         has_mce,
1632         edx_ecx,
1633         FeatureInfoFlags::MCE
1634     );
1635 
1636     check_flag!(
1637         doc = "CMPXCHG8B Instruction. The compare-and-exchange 8 bytes (64 bits) \
1638                instruction is supported (implicitly locked and atomic).",
1639         has_cmpxchg8b,
1640         edx_ecx,
1641         FeatureInfoFlags::CX8
1642     );
1643 
1644     check_flag!(
1645         doc = "APIC On-Chip. The processor contains an Advanced Programmable Interrupt \
1646                Controller (APIC), responding to memory mapped commands in the physical \
1647                address range FFFE0000H to FFFE0FFFH (by default - some processors permit \
1648                the APIC to be relocated).",
1649         has_apic,
1650         edx_ecx,
1651         FeatureInfoFlags::APIC
1652     );
1653 
1654     check_flag!(
1655         doc = "SYSENTER and SYSEXIT Instructions. The SYSENTER and SYSEXIT and \
1656                associated MSRs are supported.",
1657         has_sysenter_sysexit,
1658         edx_ecx,
1659         FeatureInfoFlags::SEP
1660     );
1661 
1662     check_flag!(
1663         doc = "Memory Type Range Registers. MTRRs are supported. The MTRRcap MSR \
1664                contains feature bits that describe what memory types are supported, how \
1665                many variable MTRRs are supported, and whether fixed MTRRs are supported.",
1666         has_mtrr,
1667         edx_ecx,
1668         FeatureInfoFlags::MTRR
1669     );
1670 
1671     check_flag!(
1672         doc = "Page Global Bit. The global bit is supported in paging-structure entries \
1673                that map a page, indicating TLB entries that are common to different \
1674                processes and need not be flushed. The CR4.PGE bit controls this feature.",
1675         has_pge,
1676         edx_ecx,
1677         FeatureInfoFlags::PGE
1678     );
1679 
1680     check_flag!(
1681         doc = "Machine Check Architecture. A value of 1 indicates the Machine Check \
1682                Architecture of reporting machine errors is supported. The MCG_CAP MSR \
1683                contains feature bits describing how many banks of error reporting MSRs \
1684                are supported.",
1685         has_mca,
1686         edx_ecx,
1687         FeatureInfoFlags::MCA
1688     );
1689 
1690     check_flag!(
1691         doc = "Conditional Move Instructions. The conditional move instruction CMOV is \
1692                supported. In addition, if x87 FPU is present as indicated by the \
1693                CPUID.FPU feature bit, then the FCOMI and FCMOV instructions are supported",
1694         has_cmov,
1695         edx_ecx,
1696         FeatureInfoFlags::CMOV
1697     );
1698 
1699     check_flag!(
1700         doc = "Page Attribute Table. Page Attribute Table is supported. This feature \
1701                augments the Memory Type Range Registers (MTRRs), allowing an operating \
1702                system to specify attributes of memory accessed through a linear address \
1703                on a 4KB granularity.",
1704         has_pat,
1705         edx_ecx,
1706         FeatureInfoFlags::PAT
1707     );
1708 
1709     check_flag!(
1710         doc = "36-Bit Page Size Extension. 4-MByte pages addressing physical memory \
1711                beyond 4 GBytes are supported with 32-bit paging. This feature indicates \
1712                that upper bits of the physical address of a 4-MByte page are encoded in \
1713                bits 20:13 of the page-directory entry. Such physical addresses are \
1714                limited by MAXPHYADDR and may be up to 40 bits in size.",
1715         has_pse36,
1716         edx_ecx,
1717         FeatureInfoFlags::PSE36
1718     );
1719 
1720     check_flag!(
1721         doc = "Processor Serial Number. The processor supports the 96-bit processor \
1722                identification number feature and the feature is enabled.",
1723         has_psn,
1724         edx_ecx,
1725         FeatureInfoFlags::PSN
1726     );
1727 
1728     check_flag!(
1729         doc = "CLFLUSH Instruction. CLFLUSH Instruction is supported.",
1730         has_clflush,
1731         edx_ecx,
1732         FeatureInfoFlags::CLFSH
1733     );
1734 
1735     check_flag!(
1736         doc = "Debug Store. The processor supports the ability to write debug \
1737                information into a memory resident buffer. This feature is used by the \
1738                branch trace store (BTS) and processor event-based sampling (PEBS) \
1739                facilities (see Chapter 23, Introduction to Virtual-Machine Extensions, \
1740                in the Intel® 64 and IA-32 Architectures Software Developers Manual, \
1741                Volume 3C).",
1742         has_ds,
1743         edx_ecx,
1744         FeatureInfoFlags::DS
1745     );
1746 
1747     check_flag!(
1748         doc = "Thermal Monitor and Software Controlled Clock Facilities. The processor \
1749                implements internal MSRs that allow processor temperature to be monitored \
1750                and processor performance to be modulated in predefined duty cycles under \
1751                software control.",
1752         has_acpi,
1753         edx_ecx,
1754         FeatureInfoFlags::ACPI
1755     );
1756 
1757     check_flag!(
1758         doc = "Intel MMX Technology. The processor supports the Intel MMX technology.",
1759         has_mmx,
1760         edx_ecx,
1761         FeatureInfoFlags::MMX
1762     );
1763 
1764     check_flag!(
1765         doc = "FXSAVE and FXRSTOR Instructions. The FXSAVE and FXRSTOR instructions are \
1766                supported for fast save and restore of the floating point context. \
1767                Presence of this bit also indicates that CR4.OSFXSR is available for an \
1768                operating system to indicate that it supports the FXSAVE and FXRSTOR \
1769                instructions.",
1770         has_fxsave_fxstor,
1771         edx_ecx,
1772         FeatureInfoFlags::FXSR
1773     );
1774 
1775     check_flag!(
1776         doc = "SSE. The processor supports the SSE extensions.",
1777         has_sse,
1778         edx_ecx,
1779         FeatureInfoFlags::SSE
1780     );
1781 
1782     check_flag!(
1783         doc = "SSE2. The processor supports the SSE2 extensions.",
1784         has_sse2,
1785         edx_ecx,
1786         FeatureInfoFlags::SSE2
1787     );
1788 
1789     check_flag!(
1790         doc = "Self Snoop. The processor supports the management of conflicting memory \
1791                types by performing a snoop of its own cache structure for transactions \
1792                issued to the bus.",
1793         has_ss,
1794         edx_ecx,
1795         FeatureInfoFlags::SS
1796     );
1797 
1798     check_flag!(
1799         doc = "Max APIC IDs reserved field is Valid. A value of 0 for HTT indicates \
1800                there is only a single logical processor in the package and software \
1801                should assume only a single APIC ID is reserved.  A value of 1 for HTT \
1802                indicates the value in CPUID.1.EBX\\[23:16\\] (the Maximum number of \
1803                addressable IDs for logical processors in this package) is valid for the \
1804                package.",
1805         has_htt,
1806         edx_ecx,
1807         FeatureInfoFlags::HTT
1808     );
1809 
1810     check_flag!(
1811         doc = "Thermal Monitor. The processor implements the thermal monitor automatic \
1812                thermal control circuitry (TCC).",
1813         has_tm,
1814         edx_ecx,
1815         FeatureInfoFlags::TM
1816     );
1817 
1818     check_flag!(
1819         doc = "Pending Break Enable. The processor supports the use of the FERR#/PBE# \
1820                pin when the processor is in the stop-clock state (STPCLK# is asserted) \
1821                to signal the processor that an interrupt is pending and that the \
1822                processor should return to normal operation to handle the interrupt. Bit \
1823                10 (PBE enable) in the IA32_MISC_ENABLE MSR enables this capability.",
1824         has_pbe,
1825         edx_ecx,
1826         FeatureInfoFlags::PBE
1827     );
1828 }
1829 
1830 bitflags! {
1831     #[derive(Default)]
1832     #[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))]
1833     struct FeatureInfoFlags: u64 {
1834 
1835         // ECX flags
1836 
1837         /// Streaming SIMD Extensions 3 (SSE3). A value of 1 indicates the processor supports this technology.
1838         const SSE3 = 1 << 0;
1839         /// PCLMULQDQ. A value of 1 indicates the processor supports the PCLMULQDQ instruction
1840         const PCLMULQDQ = 1 << 1;
1841         /// 64-bit DS Area. A value of 1 indicates the processor supports DS area using 64-bit layout
1842         const DTES64 = 1 << 2;
1843         /// MONITOR/MWAIT. A value of 1 indicates the processor supports this feature.
1844         const MONITOR = 1 << 3;
1845         /// CPL Qualified Debug Store. A value of 1 indicates the processor supports the extensions to the  Debug Store feature to allow for branch message storage qualified by CPL.
1846         const DSCPL = 1 << 4;
1847         /// Virtual Machine Extensions. A value of 1 indicates that the processor supports this technology.
1848         const VMX = 1 << 5;
1849         /// Safer Mode Extensions. A value of 1 indicates that the processor supports this technology. See Chapter 5, Safer Mode Extensions Reference.
1850         const SMX = 1 << 6;
1851         /// Enhanced Intel SpeedStep® technology. A value of 1 indicates that the processor supports this technology.
1852         const EIST = 1 << 7;
1853         /// Thermal Monitor 2. A value of 1 indicates whether the processor supports this technology.
1854         const TM2 = 1 << 8;
1855         /// A value of 1 indicates the presence of the Supplemental Streaming SIMD Extensions 3 (SSSE3). A value of 0 indicates the instruction extensions are not present in the processor
1856         const SSSE3 = 1 << 9;
1857         /// L1 Context ID. A value of 1 indicates the L1 data cache mode can be set to either adaptive mode or shared mode. A value of 0 indicates this feature is not supported. See definition of the IA32_MISC_ENABLE MSR Bit 24 (L1 Data Cache Context Mode) for details.
1858         const CNXTID = 1 << 10;
1859         /// A value of 1 indicates the processor supports FMA extensions using YMM state.
1860         const FMA = 1 << 12;
1861         /// CMPXCHG16B Available. A value of 1 indicates that the feature is available. See the CMPXCHG8B/CMPXCHG16B Compare and Exchange Bytes section. 14
1862         const CMPXCHG16B = 1 << 13;
1863         /// Perfmon and Debug Capability: A value of 1 indicates the processor supports the performance   and debug feature indication MSR IA32_PERF_CAPABILITIES.
1864         const PDCM = 1 << 15;
1865         /// Process-context identifiers. A value of 1 indicates that the processor supports PCIDs and the software may set CR4.PCIDE to 1.
1866         const PCID = 1 << 17;
1867         /// A value of 1 indicates the processor supports the ability to prefetch data from a memory mapped device.
1868         const DCA = 1 << 18;
1869         /// A value of 1 indicates that the processor supports SSE4.1.
1870         const SSE41 = 1 << 19;
1871         /// A value of 1 indicates that the processor supports SSE4.2.
1872         const SSE42 = 1 << 20;
1873         /// A value of 1 indicates that the processor supports x2APIC feature.
1874         const X2APIC = 1 << 21;
1875         /// A value of 1 indicates that the processor supports MOVBE instruction.
1876         const MOVBE = 1 << 22;
1877         /// A value of 1 indicates that the processor supports the POPCNT instruction.
1878         const POPCNT = 1 << 23;
1879         /// A value of 1 indicates that the processors local APIC timer supports one-shot operation using a TSC deadline value.
1880         const TSC_DEADLINE = 1 << 24;
1881         /// A value of 1 indicates that the processor supports the AESNI instruction extensions.
1882         const AESNI = 1 << 25;
1883         /// A value of 1 indicates that the processor supports the XSAVE/XRSTOR processor extended states feature, the XSETBV/XGETBV instructions, and XCR0.
1884         const XSAVE = 1 << 26;
1885         /// A value of 1 indicates that the OS has enabled XSETBV/XGETBV instructions to access XCR0, and support for processor extended state management using XSAVE/XRSTOR.
1886         const OSXSAVE = 1 << 27;
1887         /// A value of 1 indicates the processor supports the AVX instruction extensions.
1888         const AVX = 1 << 28;
1889         /// A value of 1 indicates that processor supports 16-bit floating-point conversion instructions.
1890         const F16C = 1 << 29;
1891         /// A value of 1 indicates that processor supports RDRAND instruction.
1892         const RDRAND = 1 << 30;
1893 
1894 
1895         // EDX flags
1896 
1897         /// Floating Point Unit On-Chip. The processor contains an x87 FPU.
1898         const FPU = 1 << (32 + 0);
1899         /// Virtual 8086 Mode Enhancements. Virtual 8086 mode enhancements, including CR4.VME for controlling the feature, CR4.PVI for protected mode virtual interrupts, software interrupt indirection, expansion of the TSS with the software indirection bitmap, and EFLAGS.VIF and EFLAGS.VIP flags.
1900         const VME = 1 << (32 + 1);
1901         /// Debugging Extensions. Support for I/O breakpoints, including CR4.DE for controlling the feature, and optional trapping of accesses to DR4 and DR5.
1902         const DE = 1 << (32 + 2);
1903         /// Page Size Extension. Large pages of size 4 MByte are supported, including CR4.PSE for controlling the feature, the defined dirty bit in PDE (Page Directory Entries), optional reserved bit trapping in CR3, PDEs, and PTEs.
1904         const PSE = 1 << (32 + 3);
1905         /// Time Stamp Counter. The RDTSC instruction is supported, including CR4.TSD for controlling privilege.
1906         const TSC = 1 << (32 + 4);
1907         /// Model Specific Registers RDMSR and WRMSR Instructions. The RDMSR and WRMSR instructions are supported. Some of the MSRs are implementation dependent.
1908         const MSR = 1 << (32 + 5);
1909         /// Physical Address Extension. Physical addresses greater than 32 bits are supported: extended page table entry formats, an extra level in the page translation tables is defined, 2-MByte pages are supported instead of 4 Mbyte pages if PAE bit is 1.
1910         const PAE = 1 << (32 + 6);
1911         /// Machine Check Exception. Exception 18 is defined for Machine Checks, including CR4.MCE for controlling the feature. This feature does not define the model-specific implementations of machine-check error logging, reporting, and processor shutdowns. Machine Check exception handlers may have to depend on processor version to do model specific processing of the exception, or test for the presence of the Machine Check feature.
1912         const MCE = 1 << (32 + 7);
1913         /// CMPXCHG8B Instruction. The compare-and-exchange 8 bytes (64 bits) instruction is supported (implicitly locked and atomic).
1914         const CX8 = 1 << (32 + 8);
1915         /// APIC On-Chip. The processor contains an Advanced Programmable Interrupt Controller (APIC), responding to memory mapped commands in the physical address range FFFE0000H to FFFE0FFFH (by default - some processors permit the APIC to be relocated).
1916         const APIC = 1 << (32 + 9);
1917         /// SYSENTER and SYSEXIT Instructions. The SYSENTER and SYSEXIT and associated MSRs are supported.
1918         const SEP = 1 << (32 + 11);
1919         /// Memory Type Range Registers. MTRRs are supported. The MTRRcap MSR contains feature bits that describe what memory types are supported, how many variable MTRRs are supported, and whether fixed MTRRs are supported.
1920         const MTRR = 1 << (32 + 12);
1921         /// Page Global Bit. The global bit is supported in paging-structure entries that map a page, indicating TLB entries that are common to different processes and need not be flushed. The CR4.PGE bit controls this feature.
1922         const PGE = 1 << (32 + 13);
1923         /// Machine Check Architecture. The Machine Check exArchitecture, which provides a compatible mechanism for error reporting in P6 family, Pentium 4, Intel Xeon processors, and future processors, is supported. The MCG_CAP MSR contains feature bits describing how many banks of error reporting MSRs are supported.
1924         const MCA = 1 << (32 + 14);
1925         /// Conditional Move Instructions. The conditional move instruction CMOV is supported. In addition, if x87 FPU is present as indicated by the CPUID.FPU feature bit, then the FCOMI and FCMOV instructions are supported
1926         const CMOV = 1 << (32 + 15);
1927         /// Page Attribute Table. Page Attribute Table is supported. This feature augments the Memory Type Range Registers (MTRRs), allowing an operating system to specify attributes of memory accessed through a linear address on a 4KB granularity.
1928         const PAT = 1 << (32 + 16);
1929         /// 36-Bit Page Size Extension. 4-MByte pages addressing physical memory beyond 4 GBytes are supported with 32-bit paging. This feature indicates that upper bits of the physical address of a 4-MByte page are encoded in bits 20:13 of the page-directory entry. Such physical addresses are limited by MAXPHYADDR and may be up to 40 bits in size.
1930         const PSE36 = 1 << (32 + 17);
1931         /// Processor Serial Number. The processor supports the 96-bit processor identification number feature and the feature is enabled.
1932         const PSN = 1 << (32 + 18);
1933         /// CLFLUSH Instruction. CLFLUSH Instruction is supported.
1934         const CLFSH = 1 << (32 + 19);
1935         /// Debug Store. The processor supports the ability to write debug information into a memory resident buffer. This feature is used by the branch trace store (BTS) and precise event-based sampling (PEBS) facilities (see Chapter 23, Introduction to Virtual-Machine Extensions, in the Intel® 64 and IA-32 Architectures Software Developers Manual, Volume 3C).
1936         const DS = 1 << (32 + 21);
1937         /// Thermal Monitor and Software Controlled Clock Facilities. The processor implements internal MSRs that allow processor temperature to be monitored and processor performance to be modulated in predefined duty cycles under software control.
1938         const ACPI = 1 << (32 + 22);
1939         /// Intel MMX Technology. The processor supports the Intel MMX technology.
1940         const MMX = 1 << (32 + 23);
1941         /// FXSAVE and FXRSTOR Instructions. The FXSAVE and FXRSTOR instructions are supported for fast save and restore of the floating point context. Presence of this bit also indicates that CR4.OSFXSR is available for an operating system to indicate that it supports the FXSAVE and FXRSTOR instructions.
1942         const FXSR = 1 << (32 + 24);
1943         /// SSE. The processor supports the SSE extensions.
1944         const SSE = 1 << (32 + 25);
1945         /// SSE2. The processor supports the SSE2 extensions.
1946         const SSE2 = 1 << (32 + 26);
1947         /// Self Snoop. The processor supports the management of conflicting memory types by performing a snoop of its own cache structure for transactions issued to the bus.
1948         const SS = 1 << (32 + 27);
1949         /// Max APIC IDs reserved field is Valid. A value of 0 for HTT indicates there is only a single logical processor in the package and software should assume only a single APIC ID is reserved.  A value of 1 for HTT indicates the value in CPUID.1.EBX[23:16] (the Maximum number of addressable IDs for logical processors in this package) is valid for the package.
1950         const HTT = 1 << (32 + 28);
1951         /// Thermal Monitor. The processor implements the thermal monitor automatic thermal control circuitry (TCC).
1952         const TM = 1 << (32 + 29);
1953         /// Pending Break Enable. The processor supports the use of the FERR#/PBE# pin when the processor is in the stop-clock state (STPCLK# is asserted) to signal the processor that an interrupt is pending and that the processor should return to normal operation to handle the interrupt. Bit 10 (PBE enable) in the IA32_MISC_ENABLE MSR enables this capability.
1954         const PBE = 1 << (32 + 31);
1955     }
1956 }
1957 
1958 #[derive(Debug, Default)]
1959 #[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))]
1960 pub struct CacheParametersIter {
1961     current: u32,
1962 }
1963 
1964 impl Iterator for CacheParametersIter {
1965     type Item = CacheParameter;
1966 
1967     /// Iterate over all caches for this CPU.
1968     /// Note: cpuid is called every-time we this function to get information
1969     /// about next cache.
next(&mut self) -> Option<CacheParameter>1970     fn next(&mut self) -> Option<CacheParameter> {
1971         let res = cpuid!(EAX_CACHE_PARAMETERS, self.current);
1972         let cp = CacheParameter {
1973             eax: res.eax,
1974             ebx: res.ebx,
1975             ecx: res.ecx,
1976             edx: res.edx,
1977         };
1978 
1979         match cp.cache_type() {
1980             CacheType::Null => None,
1981             CacheType::Reserved => None,
1982             _ => {
1983                 self.current += 1;
1984                 Some(cp)
1985             }
1986         }
1987     }
1988 }
1989 
1990 #[derive(Copy, Clone, Debug, Default)]
1991 #[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))]
1992 pub struct CacheParameter {
1993     eax: u32,
1994     ebx: u32,
1995     ecx: u32,
1996     edx: u32,
1997 }
1998 
1999 #[derive(PartialEq, Eq, Debug)]
2000 #[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))]
2001 pub enum CacheType {
2002     /// Null - No more caches
2003     Null = 0,
2004     /// Data cache
2005     Data,
2006     /// Instruction cache
2007     Instruction,
2008     /// Data and Instruction cache
2009     Unified,
2010     /// 4-31 = Reserved
2011     Reserved,
2012 }
2013 
2014 impl Default for CacheType {
default() -> CacheType2015     fn default() -> CacheType {
2016         CacheType::Null
2017     }
2018 }
2019 
2020 impl CacheParameter {
2021     /// Cache Type
cache_type(&self) -> CacheType2022     pub fn cache_type(&self) -> CacheType {
2023         let typ = get_bits(self.eax, 0, 4) as u8;
2024         match typ {
2025             0 => CacheType::Null,
2026             1 => CacheType::Data,
2027             2 => CacheType::Instruction,
2028             3 => CacheType::Unified,
2029             _ => CacheType::Reserved,
2030         }
2031     }
2032 
2033     /// Cache Level (starts at 1)
level(&self) -> u82034     pub fn level(&self) -> u8 {
2035         get_bits(self.eax, 5, 7) as u8
2036     }
2037 
2038     /// Self Initializing cache level (does not need SW initialization).
is_self_initializing(&self) -> bool2039     pub fn is_self_initializing(&self) -> bool {
2040         get_bits(self.eax, 8, 8) == 1
2041     }
2042 
2043     /// Fully Associative cache
is_fully_associative(&self) -> bool2044     pub fn is_fully_associative(&self) -> bool {
2045         get_bits(self.eax, 9, 9) == 1
2046     }
2047 
2048     /// Maximum number of addressable IDs for logical processors sharing this cache
max_cores_for_cache(&self) -> usize2049     pub fn max_cores_for_cache(&self) -> usize {
2050         (get_bits(self.eax, 14, 25) + 1) as usize
2051     }
2052 
2053     /// Maximum number of addressable IDs for processor cores in the physical package
max_cores_for_package(&self) -> usize2054     pub fn max_cores_for_package(&self) -> usize {
2055         (get_bits(self.eax, 26, 31) + 1) as usize
2056     }
2057 
2058     /// System Coherency Line Size (Bits 11-00)
coherency_line_size(&self) -> usize2059     pub fn coherency_line_size(&self) -> usize {
2060         (get_bits(self.ebx, 0, 11) + 1) as usize
2061     }
2062 
2063     /// Physical Line partitions (Bits 21-12)
physical_line_partitions(&self) -> usize2064     pub fn physical_line_partitions(&self) -> usize {
2065         (get_bits(self.ebx, 12, 21) + 1) as usize
2066     }
2067 
2068     /// Ways of associativity (Bits 31-22)
associativity(&self) -> usize2069     pub fn associativity(&self) -> usize {
2070         (get_bits(self.ebx, 22, 31) + 1) as usize
2071     }
2072 
2073     /// Number of Sets (Bits 31-00)
sets(&self) -> usize2074     pub fn sets(&self) -> usize {
2075         (self.ecx + 1) as usize
2076     }
2077 
2078     /// Write-Back Invalidate/Invalidate (Bit 0)
2079     /// False: WBINVD/INVD from threads sharing this cache acts upon lower level caches for threads sharing this cache.
2080     /// True: WBINVD/INVD is not guaranteed to act upon lower level caches of non-originating threads sharing this cache.
is_write_back_invalidate(&self) -> bool2081     pub fn is_write_back_invalidate(&self) -> bool {
2082         get_bits(self.edx, 0, 0) == 1
2083     }
2084 
2085     /// Cache Inclusiveness (Bit 1)
2086     /// False: Cache is not inclusive of lower cache levels.
2087     /// True: Cache is inclusive of lower cache levels.
is_inclusive(&self) -> bool2088     pub fn is_inclusive(&self) -> bool {
2089         get_bits(self.edx, 1, 1) == 1
2090     }
2091 
2092     /// Complex Cache Indexing (Bit 2)
2093     /// False: Direct mapped cache.
2094     /// True: A complex function is used to index the cache, potentially using all address bits.
has_complex_indexing(&self) -> bool2095     pub fn has_complex_indexing(&self) -> bool {
2096         get_bits(self.edx, 2, 2) == 1
2097     }
2098 }
2099 
2100 #[derive(Debug, Default)]
2101 #[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))]
2102 pub struct MonitorMwaitInfo {
2103     eax: u32,
2104     ebx: u32,
2105     ecx: u32,
2106     edx: u32,
2107 }
2108 
2109 impl MonitorMwaitInfo {
2110     /// Smallest monitor-line size in bytes (default is processor's monitor granularity)
smallest_monitor_line(&self) -> u162111     pub fn smallest_monitor_line(&self) -> u16 {
2112         get_bits(self.eax, 0, 15) as u16
2113     }
2114 
2115     /// Largest monitor-line size in bytes (default is processor's monitor granularity
largest_monitor_line(&self) -> u162116     pub fn largest_monitor_line(&self) -> u16 {
2117         get_bits(self.ebx, 0, 15) as u16
2118     }
2119 
2120     ///  Enumeration of Monitor-Mwait extensions (beyond EAX and EBX registers) supported
extensions_supported(&self) -> bool2121     pub fn extensions_supported(&self) -> bool {
2122         get_bits(self.ecx, 0, 0) == 1
2123     }
2124 
2125     ///  Supports treating interrupts as break-event for MWAIT, even when interrupts disabled
interrupts_as_break_event(&self) -> bool2126     pub fn interrupts_as_break_event(&self) -> bool {
2127         get_bits(self.ecx, 1, 1) == 1
2128     }
2129 
2130     /// Number of C0 sub C-states supported using MWAIT (Bits 03 - 00)
supported_c0_states(&self) -> u162131     pub fn supported_c0_states(&self) -> u16 {
2132         get_bits(self.edx, 0, 3) as u16
2133     }
2134 
2135     /// Number of C1 sub C-states supported using MWAIT (Bits 07 - 04)
supported_c1_states(&self) -> u162136     pub fn supported_c1_states(&self) -> u16 {
2137         get_bits(self.edx, 4, 7) as u16
2138     }
2139 
2140     /// Number of C2 sub C-states supported using MWAIT (Bits 11 - 08)
supported_c2_states(&self) -> u162141     pub fn supported_c2_states(&self) -> u16 {
2142         get_bits(self.edx, 8, 11) as u16
2143     }
2144 
2145     /// Number of C3 sub C-states supported using MWAIT (Bits 15 - 12)
supported_c3_states(&self) -> u162146     pub fn supported_c3_states(&self) -> u16 {
2147         get_bits(self.edx, 12, 15) as u16
2148     }
2149 
2150     /// Number of C4 sub C-states supported using MWAIT (Bits 19 - 16)
supported_c4_states(&self) -> u162151     pub fn supported_c4_states(&self) -> u16 {
2152         get_bits(self.edx, 16, 19) as u16
2153     }
2154 
2155     /// Number of C5 sub C-states supported using MWAIT (Bits 23 - 20)
supported_c5_states(&self) -> u162156     pub fn supported_c5_states(&self) -> u16 {
2157         get_bits(self.edx, 20, 23) as u16
2158     }
2159 
2160     /// Number of C6 sub C-states supported using MWAIT (Bits 27 - 24)
supported_c6_states(&self) -> u162161     pub fn supported_c6_states(&self) -> u16 {
2162         get_bits(self.edx, 24, 27) as u16
2163     }
2164 
2165     /// Number of C7 sub C-states supported using MWAIT (Bits 31 - 28)
supported_c7_states(&self) -> u162166     pub fn supported_c7_states(&self) -> u16 {
2167         get_bits(self.edx, 28, 31) as u16
2168     }
2169 }
2170 
2171 #[derive(Debug, Default)]
2172 #[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))]
2173 pub struct ThermalPowerInfo {
2174     eax: ThermalPowerFeaturesEax,
2175     ebx: u32,
2176     ecx: ThermalPowerFeaturesEcx,
2177     edx: u32,
2178 }
2179 
2180 impl ThermalPowerInfo {
2181     /// Number of Interrupt Thresholds in Digital Thermal Sensor
dts_irq_threshold(&self) -> u82182     pub fn dts_irq_threshold(&self) -> u8 {
2183         get_bits(self.ebx, 0, 3) as u8
2184     }
2185 
2186     check_flag!(
2187         doc = "Digital temperature sensor is supported if set.",
2188         has_dts,
2189         eax,
2190         ThermalPowerFeaturesEax::DTS
2191     );
2192 
2193     check_flag!(
2194         doc = "Intel Turbo Boost Technology Available (see description of \
2195                IA32_MISC_ENABLE\\[38\\]).",
2196         has_turbo_boost,
2197         eax,
2198         ThermalPowerFeaturesEax::TURBO_BOOST
2199     );
2200 
2201     check_flag!(
2202         doc = "ARAT. APIC-Timer-always-running feature is supported if set.",
2203         has_arat,
2204         eax,
2205         ThermalPowerFeaturesEax::ARAT
2206     );
2207 
2208     check_flag!(
2209         doc = "PLN. Power limit notification controls are supported if set.",
2210         has_pln,
2211         eax,
2212         ThermalPowerFeaturesEax::PLN
2213     );
2214 
2215     check_flag!(
2216         doc = "ECMD. Clock modulation duty cycle extension is supported if set.",
2217         has_ecmd,
2218         eax,
2219         ThermalPowerFeaturesEax::ECMD
2220     );
2221 
2222     check_flag!(
2223         doc = "PTM. Package thermal management is supported if set.",
2224         has_ptm,
2225         eax,
2226         ThermalPowerFeaturesEax::PTM
2227     );
2228 
2229     check_flag!(
2230         doc = "HWP. HWP base registers (IA32_PM_ENABLE[bit 0], IA32_HWP_CAPABILITIES, \
2231                IA32_HWP_REQUEST, IA32_HWP_STATUS) are supported if set.",
2232         has_hwp,
2233         eax,
2234         ThermalPowerFeaturesEax::HWP
2235     );
2236 
2237     check_flag!(
2238         doc = "HWP Notification. IA32_HWP_INTERRUPT MSR is supported if set.",
2239         has_hwp_notification,
2240         eax,
2241         ThermalPowerFeaturesEax::HWP_NOTIFICATION
2242     );
2243 
2244     check_flag!(
2245         doc = "HWP Activity Window. IA32_HWP_REQUEST[bits 41:32] is supported if set.",
2246         has_hwp_activity_window,
2247         eax,
2248         ThermalPowerFeaturesEax::HWP_ACTIVITY_WINDOW
2249     );
2250 
2251     check_flag!(
2252         doc =
2253             "HWP Energy Performance Preference. IA32_HWP_REQUEST[bits 31:24] is supported if set.",
2254         has_hwp_energy_performance_preference,
2255         eax,
2256         ThermalPowerFeaturesEax::HWP_ENERGY_PERFORMANCE_PREFERENCE
2257     );
2258 
2259     check_flag!(
2260         doc = "HWP Package Level Request. IA32_HWP_REQUEST_PKG MSR is supported if set.",
2261         has_hwp_package_level_request,
2262         eax,
2263         ThermalPowerFeaturesEax::HWP_PACKAGE_LEVEL_REQUEST
2264     );
2265 
2266     check_flag!(
2267         doc = "HDC. HDC base registers IA32_PKG_HDC_CTL, IA32_PM_CTL1, IA32_THREAD_STALL \
2268                MSRs are supported if set.",
2269         has_hdc,
2270         eax,
2271         ThermalPowerFeaturesEax::HDC
2272     );
2273 
2274     check_flag!(
2275         doc = "Intel® Turbo Boost Max Technology 3.0 available.",
2276         has_turbo_boost3,
2277         eax,
2278         ThermalPowerFeaturesEax::TURBO_BOOST_3
2279     );
2280 
2281     check_flag!(
2282         doc = "HWP Capabilities. Highest Performance change is supported if set.",
2283         has_hwp_capabilities,
2284         eax,
2285         ThermalPowerFeaturesEax::HWP_CAPABILITIES
2286     );
2287 
2288     check_flag!(
2289         doc = "HWP PECI override is supported if set.",
2290         has_hwp_peci_override,
2291         eax,
2292         ThermalPowerFeaturesEax::HWP_PECI_OVERRIDE
2293     );
2294 
2295     check_flag!(
2296         doc = "Flexible HWP is supported if set.",
2297         has_flexible_hwp,
2298         eax,
2299         ThermalPowerFeaturesEax::FLEXIBLE_HWP
2300     );
2301 
2302     check_flag!(
2303         doc = "Fast access mode for the IA32_HWP_REQUEST MSR is supported if set.",
2304         has_hwp_fast_access_mode,
2305         eax,
2306         ThermalPowerFeaturesEax::HWP_REQUEST_MSR_FAST_ACCESS
2307     );
2308 
2309     check_flag!(
2310         doc = "Ignoring Idle Logical Processor HWP request is supported if set.",
2311         has_ignore_idle_processor_hwp_request,
2312         eax,
2313         ThermalPowerFeaturesEax::IGNORE_IDLE_PROCESSOR_HWP_REQUEST
2314     );
2315 
2316     check_flag!(
2317         doc = "Hardware Coordination Feedback Capability (Presence of IA32_MPERF and \
2318                IA32_APERF). The capability to provide a measure of delivered processor \
2319                performance (since last reset of the counters), as a percentage of \
2320                expected processor performance at frequency specified in CPUID Brand \
2321                String Bits 02 - 01",
2322         has_hw_coord_feedback,
2323         ecx,
2324         ThermalPowerFeaturesEcx::HW_COORD_FEEDBACK
2325     );
2326 
2327     check_flag!(
2328         doc = "The processor supports performance-energy bias preference if \
2329                CPUID.06H:ECX.SETBH[bit 3] is set and it also implies the presence of a \
2330                new architectural MSR called IA32_ENERGY_PERF_BIAS (1B0H)",
2331         has_energy_bias_pref,
2332         ecx,
2333         ThermalPowerFeaturesEcx::ENERGY_BIAS_PREF
2334     );
2335 }
2336 
2337 bitflags! {
2338     #[derive(Default)]
2339     #[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))]
2340     struct ThermalPowerFeaturesEax: u32 {
2341         /// Digital temperature sensor is supported if set. (Bit 00)
2342         const DTS = 1 << 0;
2343         /// Intel Turbo Boost Technology Available (see description of IA32_MISC_ENABLE[38]). (Bit 01)
2344         const TURBO_BOOST = 1 << 1;
2345         /// ARAT. APIC-Timer-always-running feature is supported if set. (Bit 02)
2346         const ARAT = 1 << 2;
2347         /// Bit 3: Reserved.
2348         const RESERVED_3 = 1 << 3;
2349         /// PLN. Power limit notification controls are supported if set. (Bit 04)
2350         const PLN = 1 << 4;
2351         /// ECMD. Clock modulation duty cycle extension is supported if set. (Bit 05)
2352         const ECMD = 1 << 5;
2353         /// PTM. Package thermal management is supported if set. (Bit 06)
2354         const PTM = 1 << 6;
2355         /// Bit 07: HWP. HWP base registers (IA32_PM_ENABLE[bit 0], IA32_HWP_CAPABILITIES, IA32_HWP_REQUEST, IA32_HWP_STATUS) are supported if set.
2356         const HWP = 1 << 7;
2357         /// Bit 08: HWP_Notification. IA32_HWP_INTERRUPT MSR is supported if set.
2358         const HWP_NOTIFICATION = 1 << 8;
2359         /// Bit 09: HWP_Activity_Window. IA32_HWP_REQUEST[bits 41:32] is supported if set.
2360         const HWP_ACTIVITY_WINDOW = 1 << 9;
2361         /// Bit 10: HWP_Energy_Performance_Preference. IA32_HWP_REQUEST[bits 31:24] is supported if set.
2362         const HWP_ENERGY_PERFORMANCE_PREFERENCE = 1 << 10;
2363         /// Bit 11: HWP_Package_Level_Request. IA32_HWP_REQUEST_PKG MSR is supported if set.
2364         const HWP_PACKAGE_LEVEL_REQUEST = 1 << 11;
2365         /// Bit 12: Reserved.
2366         const RESERVED_12 = 1 << 12;
2367         /// Bit 13: HDC. HDC base registers IA32_PKG_HDC_CTL, IA32_PM_CTL1, IA32_THREAD_STALL MSRs are supported if set.
2368         const HDC = 1 << 13;
2369         /// Bit 14: Intel® Turbo Boost Max Technology 3.0 available.
2370         const TURBO_BOOST_3 = 1 << 14;
2371         /// Bit 15: HWP Capabilities. Highest Performance change is supported if set.
2372         const HWP_CAPABILITIES = 1 << 15;
2373         /// Bit 16: HWP PECI override is supported if set.
2374         const HWP_PECI_OVERRIDE = 1 << 16;
2375         /// Bit 17: Flexible HWP is supported if set.
2376         const FLEXIBLE_HWP = 1 << 17;
2377         /// Bit 18: Fast access mode for the IA32_HWP_REQUEST MSR is supported if set.
2378         const HWP_REQUEST_MSR_FAST_ACCESS = 1 << 18;
2379         /// Bit 19: Reserved.
2380         const RESERVED_19 = 1 << 19;
2381         /// Bit 20: Ignoring Idle Logical Processor HWP request is supported if set.
2382         const IGNORE_IDLE_PROCESSOR_HWP_REQUEST = 1 << 20;
2383         // Bits 31 - 21: Reserved
2384     }
2385 }
2386 
2387 bitflags! {
2388     #[derive(Default)]
2389     #[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))]
2390     struct ThermalPowerFeaturesEcx: u32 {
2391         /// Hardware Coordination Feedback Capability (Presence of IA32_MPERF and IA32_APERF). The capability to provide a measure of delivered processor performance (since last reset of the counters), as a percentage of expected processor performance at frequency specified in CPUID Brand String Bits 02 - 01
2392         const HW_COORD_FEEDBACK = 1 << 0;
2393 
2394         /// The processor supports performance-energy bias preference if CPUID.06H:ECX.SETBH[bit 3] is set and it also implies the presence of a new architectural MSR called IA32_ENERGY_PERF_BIAS (1B0H)
2395         const ENERGY_BIAS_PREF = 1 << 3;
2396     }
2397 }
2398 
2399 #[derive(Debug, Default)]
2400 #[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))]
2401 pub struct ExtendedFeatures {
2402     eax: u32,
2403     ebx: ExtendedFeaturesEbx,
2404     ecx: ExtendedFeaturesEcx,
2405     edx: u32,
2406 }
2407 
2408 impl ExtendedFeatures {
2409     check_flag!(
2410         doc = "FSGSBASE. Supports RDFSBASE/RDGSBASE/WRFSBASE/WRGSBASE if 1.",
2411         has_fsgsbase,
2412         ebx,
2413         ExtendedFeaturesEbx::FSGSBASE
2414     );
2415 
2416     check_flag!(
2417         doc = "IA32_TSC_ADJUST MSR is supported if 1.",
2418         has_tsc_adjust_msr,
2419         ebx,
2420         ExtendedFeaturesEbx::ADJUST_MSR
2421     );
2422 
2423     check_flag!(doc = "BMI1", has_bmi1, ebx, ExtendedFeaturesEbx::BMI1);
2424 
2425     check_flag!(doc = "HLE", has_hle, ebx, ExtendedFeaturesEbx::HLE);
2426 
2427     check_flag!(doc = "AVX2", has_avx2, ebx, ExtendedFeaturesEbx::AVX2);
2428 
2429     check_flag!(
2430         doc = "FDP_EXCPTN_ONLY. x87 FPU Data Pointer updated only on x87 exceptions if 1.",
2431         has_fdp,
2432         ebx,
2433         ExtendedFeaturesEbx::FDP
2434     );
2435 
2436     check_flag!(
2437         doc = "SMEP. Supports Supervisor-Mode Execution Prevention if 1.",
2438         has_smep,
2439         ebx,
2440         ExtendedFeaturesEbx::SMEP
2441     );
2442 
2443     check_flag!(doc = "BMI2", has_bmi2, ebx, ExtendedFeaturesEbx::BMI2);
2444 
2445     check_flag!(
2446         doc = "Supports Enhanced REP MOVSB/STOSB if 1.",
2447         has_rep_movsb_stosb,
2448         ebx,
2449         ExtendedFeaturesEbx::REP_MOVSB_STOSB
2450     );
2451 
2452     check_flag!(
2453         doc = "INVPCID. If 1, supports INVPCID instruction for system software that \
2454                manages process-context identifiers.",
2455         has_invpcid,
2456         ebx,
2457         ExtendedFeaturesEbx::INVPCID
2458     );
2459 
2460     check_flag!(doc = "RTM", has_rtm, ebx, ExtendedFeaturesEbx::RTM);
2461 
2462     check_flag!(
2463         doc = "Supports Intel Resource Director Technology (RDT) Monitoring capability.",
2464         has_rdtm,
2465         ebx,
2466         ExtendedFeaturesEbx::RDTM
2467     );
2468 
2469     check_flag!(
2470         doc = "Deprecates FPU CS and FPU DS values if 1.",
2471         has_fpu_cs_ds_deprecated,
2472         ebx,
2473         ExtendedFeaturesEbx::DEPRECATE_FPU_CS_DS
2474     );
2475 
2476     check_flag!(
2477         doc = "MPX. Supports Intel Memory Protection Extensions if 1.",
2478         has_mpx,
2479         ebx,
2480         ExtendedFeaturesEbx::MPX
2481     );
2482 
2483     check_flag!(
2484         doc = "Supports Intel Resource Director Technology (RDT) Allocation capability.",
2485         has_rdta,
2486         ebx,
2487         ExtendedFeaturesEbx::RDTA
2488     );
2489 
2490     check_flag!(
2491         doc = "Supports RDSEED.",
2492         has_rdseed,
2493         ebx,
2494         ExtendedFeaturesEbx::RDSEED
2495     );
2496 
2497     #[deprecated(
2498         since = "3.2",
2499         note = "Deprecated due to typo in name, users should use has_rdseed() instead."
2500     )]
2501     check_flag!(
2502         doc = "Supports RDSEED (deprecated alias).",
2503         has_rdseet,
2504         ebx,
2505         ExtendedFeaturesEbx::RDSEED
2506     );
2507 
2508     check_flag!(
2509         doc = "Supports ADX.",
2510         has_adx,
2511         ebx,
2512         ExtendedFeaturesEbx::ADX
2513     );
2514 
2515     check_flag!(doc = "SMAP. Supports Supervisor-Mode Access Prevention (and the CLAC/STAC instructions) if 1.",
2516                 has_smap,
2517                 ebx,
2518                 ExtendedFeaturesEbx::SMAP);
2519 
2520     check_flag!(
2521         doc = "Supports CLFLUSHOPT.",
2522         has_clflushopt,
2523         ebx,
2524         ExtendedFeaturesEbx::CLFLUSHOPT
2525     );
2526 
2527     check_flag!(
2528         doc = "Supports Intel Processor Trace.",
2529         has_processor_trace,
2530         ebx,
2531         ExtendedFeaturesEbx::PROCESSOR_TRACE
2532     );
2533 
2534     check_flag!(
2535         doc = "Supports SHA Instructions.",
2536         has_sha,
2537         ebx,
2538         ExtendedFeaturesEbx::SHA
2539     );
2540 
2541     check_flag!(
2542         doc = "Supports Intel® Software Guard Extensions (Intel® SGX Extensions).",
2543         has_sgx,
2544         ebx,
2545         ExtendedFeaturesEbx::SGX
2546     );
2547 
2548     check_flag!(
2549         doc = "Supports AVX512F.",
2550         has_avx512f,
2551         ebx,
2552         ExtendedFeaturesEbx::AVX512F
2553     );
2554 
2555     check_flag!(
2556         doc = "Supports AVX512DQ.",
2557         has_avx512dq,
2558         ebx,
2559         ExtendedFeaturesEbx::AVX512DQ
2560     );
2561 
2562     check_flag!(
2563         doc = "AVX512_IFMA",
2564         has_avx512_ifma,
2565         ebx,
2566         ExtendedFeaturesEbx::AVX512_IFMA
2567     );
2568 
2569     check_flag!(
2570         doc = "AVX512PF",
2571         has_avx512pf,
2572         ebx,
2573         ExtendedFeaturesEbx::AVX512PF
2574     );
2575     check_flag!(
2576         doc = "AVX512ER",
2577         has_avx512er,
2578         ebx,
2579         ExtendedFeaturesEbx::AVX512ER
2580     );
2581 
2582     check_flag!(
2583         doc = "AVX512CD",
2584         has_avx512cd,
2585         ebx,
2586         ExtendedFeaturesEbx::AVX512CD
2587     );
2588 
2589     check_flag!(
2590         doc = "AVX512BW",
2591         has_avx512bw,
2592         ebx,
2593         ExtendedFeaturesEbx::AVX512BW
2594     );
2595 
2596     check_flag!(
2597         doc = "AVX512VL",
2598         has_avx512vl,
2599         ebx,
2600         ExtendedFeaturesEbx::AVX512VL
2601     );
2602 
2603     check_flag!(doc = "CLWB", has_clwb, ebx, ExtendedFeaturesEbx::CLWB);
2604 
2605     check_flag!(
2606         doc = "Has PREFETCHWT1 (Intel® Xeon Phi™ only).",
2607         has_prefetchwt1,
2608         ecx,
2609         ExtendedFeaturesEcx::PREFETCHWT1
2610     );
2611 
2612     check_flag!(
2613         doc = "Supports user-mode instruction prevention if 1.",
2614         has_umip,
2615         ecx,
2616         ExtendedFeaturesEcx::UMIP
2617     );
2618 
2619     check_flag!(
2620         doc = "Supports protection keys for user-mode pages.",
2621         has_pku,
2622         ecx,
2623         ExtendedFeaturesEcx::PKU
2624     );
2625 
2626     check_flag!(
2627         doc = "OS has set CR4.PKE to enable protection keys (and the RDPKRU/WRPKRU instructions.",
2628         has_ospke,
2629         ecx,
2630         ExtendedFeaturesEcx::OSPKE
2631     );
2632 
2633     check_flag!(
2634         doc = "RDPID and IA32_TSC_AUX are available.",
2635         has_rdpid,
2636         ecx,
2637         ExtendedFeaturesEcx::RDPID
2638     );
2639 
2640     check_flag!(
2641         doc = "Supports SGX Launch Configuration.",
2642         has_sgx_lc,
2643         ecx,
2644         ExtendedFeaturesEcx::SGX_LC
2645     );
2646 
2647     /// The value of MAWAU used by the BNDLDX and BNDSTX instructions in 64-bit mode.
mawau_value(&self) -> u82648     pub fn mawau_value(&self) -> u8 {
2649         get_bits(self.ecx.bits(), 17, 21) as u8
2650     }
2651 }
2652 
2653 bitflags! {
2654     #[derive(Default)]
2655     #[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))]
2656     struct ExtendedFeaturesEbx: u32 {
2657         /// FSGSBASE. Supports RDFSBASE/RDGSBASE/WRFSBASE/WRGSBASE if 1. (Bit 00)
2658         const FSGSBASE = 1 << 0;
2659         /// IA32_TSC_ADJUST MSR is supported if 1. (Bit 01)
2660         const ADJUST_MSR = 1 << 1;
2661         /// Bit 02: SGX. Supports Intel® Software Guard Extensions (Intel® SGX Extensions) if 1.
2662         const SGX = 1 << 2;
2663         /// BMI1 (Bit 03)
2664         const BMI1 = 1 << 3;
2665         /// HLE (Bit 04)
2666         const HLE = 1 << 4;
2667         /// AVX2 (Bit 05)
2668         const AVX2 = 1 << 5;
2669         /// FDP_EXCPTN_ONLY. x87 FPU Data Pointer updated only on x87 exceptions if 1.
2670         const FDP = 1 << 6;
2671         /// SMEP. Supports Supervisor-Mode Execution Prevention if 1. (Bit 07)
2672         const SMEP = 1 << 7;
2673         /// BMI2 (Bit 08)
2674         const BMI2 = 1 << 8;
2675         /// Supports Enhanced REP MOVSB/STOSB if 1. (Bit 09)
2676         const REP_MOVSB_STOSB = 1 << 9;
2677         /// INVPCID. If 1, supports INVPCID instruction for system software that manages process-context identifiers. (Bit 10)
2678         const INVPCID = 1 << 10;
2679         /// RTM (Bit 11)
2680         const RTM = 1 << 11;
2681         /// Supports Intel Resource Director Technology (RDT) Monitoring. (Bit 12)
2682         const RDTM = 1 << 12;
2683         /// Deprecates FPU CS and FPU DS values if 1. (Bit 13)
2684         const DEPRECATE_FPU_CS_DS = 1 << 13;
2685         /// Deprecates FPU CS and FPU DS values if 1. (Bit 14)
2686         const MPX = 1 << 14;
2687         /// Supports Intel Resource Director Technology (RDT) Allocation capability if 1.
2688         const RDTA = 1 << 15;
2689         /// Bit 16: AVX512F.
2690         const AVX512F = 1 << 16;
2691         /// Bit 17: AVX512DQ.
2692         const AVX512DQ = 1 << 17;
2693         /// Supports RDSEED.
2694         const RDSEED = 1 << 18;
2695         /// Supports ADX.
2696         const ADX = 1 << 19;
2697         /// SMAP. Supports Supervisor-Mode Access Prevention (and the CLAC/STAC instructions) if 1.
2698         const SMAP = 1 << 20;
2699         /// Bit 21: AVX512_IFMA.
2700         const AVX512_IFMA = 1 << 21;
2701         // Bit 22: Reserved.
2702         /// Bit 23: CLFLUSHOPT
2703         const CLFLUSHOPT = 1 << 23;
2704         /// Bit 24: CLWB.
2705         const CLWB = 1 << 24;
2706         /// Bit 25: Intel Processor Trace
2707         const PROCESSOR_TRACE = 1 << 25;
2708         /// Bit 26: AVX512PF. (Intel® Xeon Phi™ only.)
2709         const AVX512PF = 1 << 26;
2710         /// Bit 27: AVX512ER. (Intel® Xeon Phi™ only.)
2711         const AVX512ER = 1 << 27;
2712         /// Bit 28: AVX512CD.
2713         const AVX512CD = 1 << 28;
2714         /// Bit 29: Intel SHA Extensions
2715         const SHA = 1 << 29;
2716         /// Bit 30: AVX512BW.
2717         const AVX512BW = 1 << 30;
2718         /// Bit 31: AVX512VL.
2719         const AVX512VL = 1 << 31;
2720     }
2721 }
2722 
2723 bitflags! {
2724     #[derive(Default)]
2725     #[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))]
2726     struct ExtendedFeaturesEcx: u32 {
2727         /// Bit 0: Prefetch WT1. (Intel® Xeon Phi™ only).
2728         const PREFETCHWT1 = 1 << 0;
2729 
2730         // Bit 01: AVX512_VBMI
2731         const AVX512VBMI = 1 << 1;
2732 
2733         /// Bit 02: UMIP. Supports user-mode instruction prevention if 1.
2734         const UMIP = 1 << 2;
2735 
2736         /// Bit 03: PKU. Supports protection keys for user-mode pages if 1.
2737         const PKU = 1 << 3;
2738 
2739         /// Bit 04: OSPKE. If 1, OS has set CR4.PKE to enable protection keys (and the RDPKRU/WRPKRU instruc-tions).
2740         const OSPKE = 1 << 4;
2741 
2742         // Bits 16 - 5: Reserved.
2743         // Bits 21 - 17: The value of MAWAU used by the BNDLDX and BNDSTX instructions in 64-bit mode.
2744 
2745 
2746         /// Bit 22: RDPID. RDPID and IA32_TSC_AUX are available if 1.
2747         const RDPID = 1 << 22;
2748 
2749         // Bits 29 - 23: Reserved.
2750 
2751         /// Bit 30: SGX_LC. Supports SGX Launch Configuration if 1.
2752         const SGX_LC = 1 << 30;
2753     }
2754 }
2755 
2756 #[derive(Debug, Default)]
2757 #[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))]
2758 pub struct DirectCacheAccessInfo {
2759     eax: u32,
2760 }
2761 
2762 impl DirectCacheAccessInfo {
2763     /// Value of bits \[31:0\] of IA32_PLATFORM_DCA_CAP MSR (address 1F8H)
get_dca_cap_value(&self) -> u322764     pub fn get_dca_cap_value(&self) -> u32 {
2765         self.eax
2766     }
2767 }
2768 
2769 #[derive(Debug, Default)]
2770 #[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))]
2771 pub struct PerformanceMonitoringInfo {
2772     eax: u32,
2773     ebx: PerformanceMonitoringFeaturesEbx,
2774     ecx: u32,
2775     edx: u32,
2776 }
2777 
2778 impl PerformanceMonitoringInfo {
2779     /// Version ID of architectural performance monitoring. (Bits 07 - 00)
version_id(&self) -> u82780     pub fn version_id(&self) -> u8 {
2781         get_bits(self.eax, 0, 7) as u8
2782     }
2783 
2784     /// Number of general-purpose performance monitoring counter per logical processor. (Bits 15- 08)
number_of_counters(&self) -> u82785     pub fn number_of_counters(&self) -> u8 {
2786         get_bits(self.eax, 8, 15) as u8
2787     }
2788 
2789     /// Bit width of general-purpose, performance monitoring counter. (Bits 23 - 16)
counter_bit_width(&self) -> u82790     pub fn counter_bit_width(&self) -> u8 {
2791         get_bits(self.eax, 16, 23) as u8
2792     }
2793 
2794     /// Length of EBX bit vector to enumerate architectural performance monitoring events. (Bits 31 - 24)
ebx_length(&self) -> u82795     pub fn ebx_length(&self) -> u8 {
2796         get_bits(self.eax, 24, 31) as u8
2797     }
2798 
2799     /// Number of fixed-function performance counters (if Version ID > 1). (Bits 04 - 00)
fixed_function_counters(&self) -> u82800     pub fn fixed_function_counters(&self) -> u8 {
2801         get_bits(self.edx, 0, 4) as u8
2802     }
2803 
2804     /// Bit width of fixed-function performance counters (if Version ID > 1). (Bits 12- 05)
fixed_function_counters_bit_width(&self) -> u82805     pub fn fixed_function_counters_bit_width(&self) -> u8 {
2806         get_bits(self.edx, 5, 12) as u8
2807     }
2808 
2809     check_bit_fn!(
2810         doc = "AnyThread deprecation",
2811         has_any_thread_deprecation,
2812         edx,
2813         15
2814     );
2815 
2816     check_flag!(
2817         doc = "Core cycle event not available if 1.",
2818         is_core_cyc_ev_unavailable,
2819         ebx,
2820         PerformanceMonitoringFeaturesEbx::CORE_CYC_EV_UNAVAILABLE
2821     );
2822 
2823     check_flag!(
2824         doc = "Instruction retired event not available if 1.",
2825         is_inst_ret_ev_unavailable,
2826         ebx,
2827         PerformanceMonitoringFeaturesEbx::INST_RET_EV_UNAVAILABLE
2828     );
2829 
2830     check_flag!(
2831         doc = "Reference cycles event not available if 1.",
2832         is_ref_cycle_ev_unavailable,
2833         ebx,
2834         PerformanceMonitoringFeaturesEbx::REF_CYC_EV_UNAVAILABLE
2835     );
2836 
2837     check_flag!(
2838         doc = "Last-level cache reference event not available if 1.",
2839         is_cache_ref_ev_unavailable,
2840         ebx,
2841         PerformanceMonitoringFeaturesEbx::CACHE_REF_EV_UNAVAILABLE
2842     );
2843 
2844     check_flag!(
2845         doc = "Last-level cache misses event not available if 1.",
2846         is_ll_cache_miss_ev_unavailable,
2847         ebx,
2848         PerformanceMonitoringFeaturesEbx::LL_CACHE_MISS_EV_UNAVAILABLE
2849     );
2850 
2851     check_flag!(
2852         doc = "Branch instruction retired event not available if 1.",
2853         is_branch_inst_ret_ev_unavailable,
2854         ebx,
2855         PerformanceMonitoringFeaturesEbx::BRANCH_INST_RET_EV_UNAVAILABLE
2856     );
2857 
2858     check_flag!(
2859         doc = "Branch mispredict retired event not available if 1.",
2860         is_branch_midpred_ev_unavailable,
2861         ebx,
2862         PerformanceMonitoringFeaturesEbx::BRANCH_MISPRED_EV_UNAVAILABLE
2863     );
2864 }
2865 
2866 bitflags! {
2867     #[derive(Default)]
2868     #[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))]
2869     struct PerformanceMonitoringFeaturesEbx: u32 {
2870         /// Core cycle event not available if 1. (Bit 0)
2871         const CORE_CYC_EV_UNAVAILABLE = 1 << 0;
2872         /// Instruction retired event not available if 1. (Bit 01)
2873         const INST_RET_EV_UNAVAILABLE = 1 << 1;
2874         /// Reference cycles event not available if 1. (Bit 02)
2875         const REF_CYC_EV_UNAVAILABLE = 1 << 2;
2876         /// Last-level cache reference event not available if 1. (Bit 03)
2877         const CACHE_REF_EV_UNAVAILABLE = 1 << 3;
2878         /// Last-level cache misses event not available if 1. (Bit 04)
2879         const LL_CACHE_MISS_EV_UNAVAILABLE = 1 << 4;
2880         /// Branch instruction retired event not available if 1. (Bit 05)
2881         const BRANCH_INST_RET_EV_UNAVAILABLE = 1 << 5;
2882         /// Branch mispredict retired event not available if 1. (Bit 06)
2883         const BRANCH_MISPRED_EV_UNAVAILABLE = 1 << 6;
2884     }
2885 }
2886 
2887 /// Iterates over the system topology in order to retrieve more
2888 /// system information at each level of the topology.
2889 #[derive(Debug, Default)]
2890 #[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))]
2891 pub struct ExtendedTopologyIter {
2892     level: u32,
2893 }
2894 
2895 /// Gives detailed information about the current level in the topology
2896 /// (how many cores, what type etc.).
2897 #[derive(Default)]
2898 #[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))]
2899 pub struct ExtendedTopologyLevel {
2900     eax: u32,
2901     ebx: u32,
2902     ecx: u32,
2903     edx: u32,
2904 }
2905 
2906 impl fmt::Debug for ExtendedTopologyLevel {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result2907     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2908         f.debug_struct("ExtendedTopologyLevel")
2909             .field("processors", &self.processors())
2910             .field("number", &self.level_number())
2911             .field("type", &self.level_type())
2912             .field("x2apic_id", &self.x2apic_id())
2913             .field("next_apic_id", &self.shift_right_for_next_apic_id())
2914             .finish()
2915     }
2916 }
2917 
2918 impl ExtendedTopologyLevel {
2919     /// Number of logical processors at this level type.
2920     /// The number reflects configuration as shipped.
processors(&self) -> u162921     pub fn processors(&self) -> u16 {
2922         get_bits(self.ebx, 0, 15) as u16
2923     }
2924 
2925     /// Level number.
level_number(&self) -> u82926     pub fn level_number(&self) -> u8 {
2927         get_bits(self.ecx, 0, 7) as u8
2928     }
2929 
2930     // Level type.
level_type(&self) -> TopologyType2931     pub fn level_type(&self) -> TopologyType {
2932         match get_bits(self.ecx, 8, 15) {
2933             0 => TopologyType::Invalid,
2934             1 => TopologyType::SMT,
2935             2 => TopologyType::Core,
2936             _ => unreachable!(),
2937         }
2938     }
2939 
2940     /// x2APIC ID the current logical processor. (Bits 31-00)
x2apic_id(&self) -> u322941     pub fn x2apic_id(&self) -> u32 {
2942         self.edx
2943     }
2944 
2945     /// Number of bits to shift right on x2APIC ID to get a unique topology ID of the next level type. (Bits 04-00)
2946     /// All logical processors with the same next level ID share current level.
shift_right_for_next_apic_id(&self) -> u322947     pub fn shift_right_for_next_apic_id(&self) -> u32 {
2948         get_bits(self.eax, 0, 4)
2949     }
2950 }
2951 
2952 /// What type of core we have at this level in the topology (real CPU or hyper-threaded).
2953 #[derive(PartialEq, Eq, Debug)]
2954 #[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))]
2955 pub enum TopologyType {
2956     Invalid = 0,
2957     /// Hyper-thread (Simultaneous multithreading)
2958     SMT = 1,
2959     Core = 2,
2960 }
2961 
2962 impl Default for TopologyType {
default() -> TopologyType2963     fn default() -> TopologyType {
2964         TopologyType::Invalid
2965     }
2966 }
2967 
2968 impl Iterator for ExtendedTopologyIter {
2969     type Item = ExtendedTopologyLevel;
2970 
next(&mut self) -> Option<ExtendedTopologyLevel>2971     fn next(&mut self) -> Option<ExtendedTopologyLevel> {
2972         let res = cpuid!(EAX_EXTENDED_TOPOLOGY_INFO, self.level);
2973         self.level += 1;
2974 
2975         let et = ExtendedTopologyLevel {
2976             eax: res.eax,
2977             ebx: res.ebx,
2978             ecx: res.ecx,
2979             edx: res.edx,
2980         };
2981 
2982         match et.level_type() {
2983             TopologyType::Invalid => None,
2984             _ => Some(et),
2985         }
2986     }
2987 }
2988 
2989 bitflags! {
2990     #[derive(Default)]
2991     #[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))]
2992     struct ExtendedStateInfoXCR0Flags: u32 {
2993         /// legacy x87 (Bit 00).
2994         const LEGACY_X87 = 1 << 0;
2995 
2996         /// 128-bit SSE (Bit 01).
2997         const SSE128 = 1 << 1;
2998 
2999         /// 256-bit AVX (Bit 02).
3000         const AVX256 = 1 << 2;
3001 
3002         /// MPX BNDREGS (Bit 03).
3003         const MPX_BNDREGS = 1 << 3;
3004 
3005         /// MPX BNDCSR (Bit 04).
3006         const MPX_BNDCSR = 1 << 4;
3007 
3008         /// AVX512 OPMASK (Bit 05).
3009         const AVX512_OPMASK = 1 << 5;
3010 
3011         /// AVX ZMM Hi256 (Bit 06).
3012         const AVX512_ZMM_HI256 = 1 << 6;
3013 
3014         /// AVX 512 ZMM Hi16 (Bit 07).
3015         const AVX512_ZMM_HI16 = 1 << 7;
3016 
3017         /// PKRU state (Bit 09).
3018         const PKRU = 1 << 9;
3019 
3020         /// IA32_XSS HDC State (Bit 13).
3021         const IA32_XSS_HDC = 1 << 13;
3022     }
3023 }
3024 
3025 bitflags! {
3026     #[derive(Default)]
3027     #[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))]
3028     struct ExtendedStateInfoXSSFlags: u32 {
3029         /// IA32_XSS PT (Trace Packet) State (Bit 08).
3030         const PT = 1 << 8;
3031 
3032         /// IA32_XSS HDC State (Bit 13).
3033         const HDC = 1 << 13;
3034     }
3035 }
3036 
3037 #[derive(Debug, Default)]
3038 #[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))]
3039 pub struct ExtendedStateInfo {
3040     eax: ExtendedStateInfoXCR0Flags,
3041     ebx: u32,
3042     ecx: u32,
3043     edx: u32,
3044     eax1: u32,
3045     ebx1: u32,
3046     ecx1: ExtendedStateInfoXSSFlags,
3047     edx1: u32,
3048 }
3049 
3050 impl ExtendedStateInfo {
3051     check_flag!(
3052         doc = "Support for legacy x87 in XCR0.",
3053         xcr0_supports_legacy_x87,
3054         eax,
3055         ExtendedStateInfoXCR0Flags::LEGACY_X87
3056     );
3057 
3058     check_flag!(
3059         doc = "Support for SSE 128-bit in XCR0.",
3060         xcr0_supports_sse_128,
3061         eax,
3062         ExtendedStateInfoXCR0Flags::SSE128
3063     );
3064 
3065     check_flag!(
3066         doc = "Support for AVX 256-bit in XCR0.",
3067         xcr0_supports_avx_256,
3068         eax,
3069         ExtendedStateInfoXCR0Flags::AVX256
3070     );
3071 
3072     check_flag!(
3073         doc = "Support for MPX BNDREGS in XCR0.",
3074         xcr0_supports_mpx_bndregs,
3075         eax,
3076         ExtendedStateInfoXCR0Flags::MPX_BNDREGS
3077     );
3078 
3079     check_flag!(
3080         doc = "Support for MPX BNDCSR in XCR0.",
3081         xcr0_supports_mpx_bndcsr,
3082         eax,
3083         ExtendedStateInfoXCR0Flags::MPX_BNDCSR
3084     );
3085 
3086     check_flag!(
3087         doc = "Support for AVX512 OPMASK in XCR0.",
3088         xcr0_supports_avx512_opmask,
3089         eax,
3090         ExtendedStateInfoXCR0Flags::AVX512_OPMASK
3091     );
3092 
3093     check_flag!(
3094         doc = "Support for AVX512 ZMM Hi256 XCR0.",
3095         xcr0_supports_avx512_zmm_hi256,
3096         eax,
3097         ExtendedStateInfoXCR0Flags::AVX512_ZMM_HI256
3098     );
3099 
3100     check_flag!(
3101         doc = "Support for AVX512 ZMM Hi16 in XCR0.",
3102         xcr0_supports_avx512_zmm_hi16,
3103         eax,
3104         ExtendedStateInfoXCR0Flags::AVX512_ZMM_HI16
3105     );
3106 
3107     check_flag!(
3108         doc = "Support for PKRU in XCR0.",
3109         xcr0_supports_pkru,
3110         eax,
3111         ExtendedStateInfoXCR0Flags::PKRU
3112     );
3113 
3114     check_flag!(
3115         doc = "Support for PT in IA32_XSS.",
3116         ia32_xss_supports_pt,
3117         ecx1,
3118         ExtendedStateInfoXSSFlags::PT
3119     );
3120 
3121     check_flag!(
3122         doc = "Support for HDC in IA32_XSS.",
3123         ia32_xss_supports_hdc,
3124         ecx1,
3125         ExtendedStateInfoXSSFlags::HDC
3126     );
3127 
3128     /// Maximum size (bytes, from the beginning of the XSAVE/XRSTOR save area) required by
3129     /// enabled features in XCR0. May be different than ECX if some features at the end of the XSAVE save area
3130     /// are not enabled.
xsave_area_size_enabled_features(&self) -> u323131     pub fn xsave_area_size_enabled_features(&self) -> u32 {
3132         self.ebx
3133     }
3134 
3135     /// Maximum size (bytes, from the beginning of the XSAVE/XRSTOR save area) of the
3136     /// XSAVE/XRSTOR save area required by all supported features in the processor,
3137     /// i.e all the valid bit fields in XCR0.
xsave_area_size_supported_features(&self) -> u323138     pub fn xsave_area_size_supported_features(&self) -> u32 {
3139         self.ecx
3140     }
3141 
3142     /// CPU has xsaveopt feature.
has_xsaveopt(&self) -> bool3143     pub fn has_xsaveopt(&self) -> bool {
3144         self.eax1 & 0x1 > 0
3145     }
3146 
3147     /// Supports XSAVEC and the compacted form of XRSTOR if set.
has_xsavec(&self) -> bool3148     pub fn has_xsavec(&self) -> bool {
3149         self.eax1 & 0b10 > 0
3150     }
3151 
3152     /// Supports XGETBV with ECX = 1 if set.
has_xgetbv(&self) -> bool3153     pub fn has_xgetbv(&self) -> bool {
3154         self.eax1 & 0b100 > 0
3155     }
3156 
3157     /// Supports XSAVES/XRSTORS and IA32_XSS if set.
has_xsaves_xrstors(&self) -> bool3158     pub fn has_xsaves_xrstors(&self) -> bool {
3159         self.eax1 & 0b1000 > 0
3160     }
3161 
3162     /// The size in bytes of the XSAVE area containing all states enabled by XCRO | IA32_XSS.
xsave_size(&self) -> u323163     pub fn xsave_size(&self) -> u32 {
3164         self.ebx1
3165     }
3166 
3167     /// Iterator over extended state enumeration levels >= 2.
iter(&self) -> ExtendedStateIter3168     pub fn iter(&self) -> ExtendedStateIter {
3169         ExtendedStateIter {
3170             level: 1,
3171             supported_xcr0: self.eax.bits(),
3172             supported_xss: self.ecx1.bits(),
3173         }
3174     }
3175 }
3176 
3177 #[derive(Debug, Default)]
3178 #[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))]
3179 pub struct ExtendedStateIter {
3180     level: u32,
3181     supported_xcr0: u32,
3182     supported_xss: u32,
3183 }
3184 
3185 /// When CPUID executes with EAX set to 0DH and ECX = n (n > 1,
3186 /// and is a valid sub-leaf index), the processor returns information
3187 /// about the size and offset of each processor extended state save area
3188 /// within the XSAVE/XRSTOR area. Software can use the forward-extendable
3189 /// technique depicted below to query the valid sub-leaves and obtain size
3190 /// and offset information for each processor extended state save area:///
3191 ///
3192 /// For i = 2 to 62 // sub-leaf 1 is reserved
3193 ///   IF (CPUID.(EAX=0DH, ECX=0):VECTOR\[i\] = 1 ) // VECTOR is the 64-bit value of EDX:EAX
3194 ///     Execute CPUID.(EAX=0DH, ECX = i) to examine size and offset for sub-leaf i;
3195 /// FI;
3196 impl Iterator for ExtendedStateIter {
3197     type Item = ExtendedState;
3198 
next(&mut self) -> Option<ExtendedState>3199     fn next(&mut self) -> Option<ExtendedState> {
3200         self.level += 1;
3201         if self.level > 31 {
3202             return None;
3203         }
3204 
3205         let bit = 1 << self.level;
3206         if (self.supported_xcr0 & bit > 0) || (self.supported_xss & bit > 0) {
3207             let res = cpuid!(EAX_EXTENDED_STATE_INFO, self.level);
3208             return Some(ExtendedState {
3209                 subleaf: self.level,
3210                 eax: res.eax,
3211                 ebx: res.ebx,
3212                 ecx: res.ecx,
3213             });
3214         }
3215 
3216         self.next()
3217     }
3218 }
3219 
3220 #[derive(Debug, Default)]
3221 #[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))]
3222 pub struct ExtendedState {
3223     pub subleaf: u32,
3224     eax: u32,
3225     ebx: u32,
3226     ecx: u32,
3227 }
3228 
3229 impl ExtendedState {
3230     /// The size in bytes (from the offset specified in EBX) of the save area
3231     /// for an extended state feature associated with a valid sub-leaf index, n.
3232     /// This field reports 0 if the sub-leaf index, n, is invalid.
size(&self) -> u323233     pub fn size(&self) -> u32 {
3234         self.eax
3235     }
3236 
3237     /// The offset in bytes of this extended state components save area
3238     /// from the beginning of the XSAVE/XRSTOR area.
offset(&self) -> u323239     pub fn offset(&self) -> u32 {
3240         self.ebx
3241     }
3242 
3243     /// True if the bit n (corresponding to the sub-leaf index)
3244     /// is supported in the IA32_XSS MSR;
is_in_ia32_xss(&self) -> bool3245     pub fn is_in_ia32_xss(&self) -> bool {
3246         self.ecx & 0b1 > 0
3247     }
3248 
3249     /// True if bit n is supported in XCR0.
is_in_xcr0(&self) -> bool3250     pub fn is_in_xcr0(&self) -> bool {
3251         self.ecx & 0b1 == 0
3252     }
3253 
3254     /// Returns true when the compacted format of an XSAVE area is used,
3255     /// this extended state component located on the next 64-byte
3256     /// boundary following the preceding state component
3257     /// (otherwise, it is located immediately following the preceding state component).
is_compacted_format(&self) -> bool3258     pub fn is_compacted_format(&self) -> bool {
3259         self.ecx & 0b10 > 0
3260     }
3261 }
3262 
3263 #[derive(Debug, Default)]
3264 #[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))]
3265 pub struct RdtMonitoringInfo {
3266     ebx: u32,
3267     edx: u32,
3268 }
3269 
3270 /// Intel Resource Director Technology (Intel RDT) Monitoring Enumeration Sub-leaf (EAX = 0FH, ECX = 0 and ECX = 1)
3271 impl RdtMonitoringInfo {
3272     /// Maximum range (zero-based) of RMID within this physical processor of all types.
rmid_range(&self) -> u323273     pub fn rmid_range(&self) -> u32 {
3274         self.ebx
3275     }
3276 
3277     check_bit_fn!(
3278         doc = "Supports L3 Cache Intel RDT Monitoring.",
3279         has_l3_monitoring,
3280         edx,
3281         1
3282     );
3283 
3284     /// L3 Cache Monitoring.
l3_monitoring(&self) -> Option<L3MonitoringInfo>3285     pub fn l3_monitoring(&self) -> Option<L3MonitoringInfo> {
3286         if self.has_l3_monitoring() {
3287             let res = cpuid!(EAX_RDT_MONITORING, 1);
3288             return Some(L3MonitoringInfo {
3289                 ebx: res.ebx,
3290                 ecx: res.ecx,
3291                 edx: res.edx,
3292             });
3293         } else {
3294             return None;
3295         }
3296     }
3297 }
3298 
3299 #[derive(Debug, Default)]
3300 #[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))]
3301 pub struct L3MonitoringInfo {
3302     ebx: u32,
3303     ecx: u32,
3304     edx: u32,
3305 }
3306 
3307 impl L3MonitoringInfo {
3308     /// Conversion factor from reported IA32_QM_CTR value to occupancy metric (bytes).
conversion_factor(&self) -> u323309     pub fn conversion_factor(&self) -> u32 {
3310         self.ebx
3311     }
3312 
3313     /// Maximum range (zero-based) of RMID of L3.
maximum_rmid_range(&self) -> u323314     pub fn maximum_rmid_range(&self) -> u32 {
3315         self.ecx
3316     }
3317 
3318     check_bit_fn!(
3319         doc = "Supports occupancy monitoring.",
3320         has_occupancy_monitoring,
3321         edx,
3322         0
3323     );
3324 
3325     check_bit_fn!(
3326         doc = "Supports total bandwidth monitoring.",
3327         has_total_bandwidth_monitoring,
3328         edx,
3329         1
3330     );
3331 
3332     check_bit_fn!(
3333         doc = "Supports local bandwidth monitoring.",
3334         has_local_bandwidth_monitoring,
3335         edx,
3336         2
3337     );
3338 }
3339 
3340 #[derive(Debug, Default)]
3341 #[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))]
3342 pub struct RdtAllocationInfo {
3343     ebx: u32,
3344 }
3345 
3346 impl RdtAllocationInfo {
3347     check_bit_fn!(doc = "Supports L3 Cache Allocation.", has_l3_cat, ebx, 1);
3348 
3349     check_bit_fn!(doc = "Supports L2 Cache Allocation.", has_l2_cat, ebx, 2);
3350 
3351     check_bit_fn!(
3352         doc = "Supports Memory Bandwidth Allocation.",
3353         has_memory_bandwidth_allocation,
3354         ebx,
3355         1
3356     );
3357 
3358     /// L3 Cache Allocation Information.
l3_cat(&self) -> Option<L3CatInfo>3359     pub fn l3_cat(&self) -> Option<L3CatInfo> {
3360         if self.has_l3_cat() {
3361             let res = cpuid!(EAX_RDT_ALLOCATION, 1);
3362             return Some(L3CatInfo {
3363                 eax: res.eax,
3364                 ebx: res.ebx,
3365                 ecx: res.ecx,
3366                 edx: res.edx,
3367             });
3368         } else {
3369             return None;
3370         }
3371     }
3372 
3373     /// L2 Cache Allocation Information.
l2_cat(&self) -> Option<L2CatInfo>3374     pub fn l2_cat(&self) -> Option<L2CatInfo> {
3375         if self.has_l2_cat() {
3376             let res = cpuid!(EAX_RDT_ALLOCATION, 2);
3377             return Some(L2CatInfo {
3378                 eax: res.eax,
3379                 ebx: res.ebx,
3380                 edx: res.edx,
3381             });
3382         } else {
3383             return None;
3384         }
3385     }
3386 
3387     /// Memory Bandwidth Allocation Information.
memory_bandwidth_allocation(&self) -> Option<MemBwAllocationInfo>3388     pub fn memory_bandwidth_allocation(&self) -> Option<MemBwAllocationInfo> {
3389         if self.has_l2_cat() {
3390             let res = cpuid!(EAX_RDT_ALLOCATION, 3);
3391             return Some(MemBwAllocationInfo {
3392                 eax: res.eax,
3393                 ecx: res.ecx,
3394                 edx: res.edx,
3395             });
3396         } else {
3397             return None;
3398         }
3399     }
3400 }
3401 
3402 /// L3 Cache Allocation Technology Enumeration Sub-leaf (EAX = 10H, ECX = ResID = 1).
3403 #[derive(Debug, Default)]
3404 #[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))]
3405 pub struct L3CatInfo {
3406     eax: u32,
3407     ebx: u32,
3408     ecx: u32,
3409     edx: u32,
3410 }
3411 
3412 impl L3CatInfo {
3413     /// Length of the capacity bit mask using minus-one notation.
capacity_mask_length(&self) -> u83414     pub fn capacity_mask_length(&self) -> u8 {
3415         get_bits(self.eax, 0, 4) as u8
3416     }
3417 
3418     /// Bit-granular map of isolation/contention of allocation units.
isolation_bitmap(&self) -> u323419     pub fn isolation_bitmap(&self) -> u32 {
3420         self.ebx
3421     }
3422 
3423     /// Highest COS number supported for this Leaf.
highest_cos(&self) -> u163424     pub fn highest_cos(&self) -> u16 {
3425         get_bits(self.edx, 0, 15) as u16
3426     }
3427 
3428     check_bit_fn!(
3429         doc = "Is Code and Data Prioritization Technology supported?",
3430         has_code_data_prioritization,
3431         ecx,
3432         2
3433     );
3434 }
3435 
3436 /// L2 Cache Allocation Technology Enumeration Sub-leaf (EAX = 10H, ECX = ResID = 2).
3437 #[derive(Debug, Default)]
3438 #[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))]
3439 pub struct L2CatInfo {
3440     eax: u32,
3441     ebx: u32,
3442     edx: u32,
3443 }
3444 
3445 impl L2CatInfo {
3446     /// Length of the capacity bit mask using minus-one notation.
capacity_mask_length(&self) -> u83447     pub fn capacity_mask_length(&self) -> u8 {
3448         get_bits(self.eax, 0, 4) as u8
3449     }
3450 
3451     /// Bit-granular map of isolation/contention of allocation units.
isolation_bitmap(&self) -> u323452     pub fn isolation_bitmap(&self) -> u32 {
3453         self.ebx
3454     }
3455 
3456     /// Highest COS number supported for this Leaf.
highest_cos(&self) -> u163457     pub fn highest_cos(&self) -> u16 {
3458         get_bits(self.edx, 0, 15) as u16
3459     }
3460 }
3461 
3462 /// Memory Bandwidth Allocation Enumeration Sub-leaf (EAX = 10H, ECX = ResID = 3).
3463 #[derive(Debug, Default)]
3464 #[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))]
3465 pub struct MemBwAllocationInfo {
3466     eax: u32,
3467     ecx: u32,
3468     edx: u32,
3469 }
3470 
3471 impl MemBwAllocationInfo {
3472     /// Reports the maximum MBA throttling value supported for the corresponding ResID using minus-one notation.
max_hba_throttling(&self) -> u163473     pub fn max_hba_throttling(&self) -> u16 {
3474         get_bits(self.eax, 0, 11) as u16
3475     }
3476 
3477     /// Highest COS number supported for this Leaf.
highest_cos(&self) -> u163478     pub fn highest_cos(&self) -> u16 {
3479         get_bits(self.edx, 0, 15) as u16
3480     }
3481 
3482     check_bit_fn!(
3483         doc = "Reports whether the response of the delay values is linear.",
3484         has_linear_response_delay,
3485         ecx,
3486         2
3487     );
3488 }
3489 
3490 /// Intel SGX Capability Enumeration Leaf, sub-leaf 0 (EAX = 12H, ECX = 0 and ECX = 1)
3491 #[derive(Debug, Default)]
3492 #[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))]
3493 pub struct SgxInfo {
3494     eax: u32,
3495     ebx: u32,
3496     ecx: u32,
3497     edx: u32,
3498     eax1: u32,
3499     ebx1: u32,
3500     ecx1: u32,
3501     edx1: u32,
3502 }
3503 
3504 impl SgxInfo {
3505     check_bit_fn!(doc = "Has SGX1 support.", has_sgx1, eax, 0);
3506     check_bit_fn!(doc = "Has SGX2 support.", has_sgx2, eax, 1);
3507 
3508     check_bit_fn!(
3509         doc = "Supports ENCLV instruction leaves EINCVIRTCHILD, EDECVIRTCHILD, and ESETCONTEXT.",
3510         has_enclv_leaves_einvirtchild_edecvirtchild_esetcontext,
3511         eax,
3512         5
3513     );
3514 
3515     check_bit_fn!(
3516         doc = "Supports ENCLS instruction leaves ETRACKC, ERDINFO, ELDBC, and ELDUC.",
3517         has_encls_leaves_etrackc_erdinfo_eldbc_elduc,
3518         eax,
3519         6
3520     );
3521 
3522     /// Bit vector of supported extended SGX features.
miscselect(&self) -> u323523     pub fn miscselect(&self) -> u32 {
3524         self.ebx
3525     }
3526 
3527     ///  The maximum supported enclave size in non-64-bit mode is 2^retval.
max_enclave_size_non_64bit(&self) -> u83528     pub fn max_enclave_size_non_64bit(&self) -> u8 {
3529         get_bits(self.edx, 0, 7) as u8
3530     }
3531 
3532     ///  The maximum supported enclave size in 64-bit mode is 2^retval.
max_enclave_size_64bit(&self) -> u83533     pub fn max_enclave_size_64bit(&self) -> u8 {
3534         get_bits(self.edx, 8, 15) as u8
3535     }
3536 
3537     /// Reports the valid bits of SECS.ATTRIBUTES\[127:0\] that software can set with ECREATE.
secs_attributes(&self) -> (u64, u64)3538     pub fn secs_attributes(&self) -> (u64, u64) {
3539         let lower = self.eax1 as u64 | (self.ebx1 as u64) << 32;
3540         let upper = self.ecx1 as u64 | (self.edx1 as u64) << 32;
3541         (lower, upper)
3542     }
3543     /// Iterator over SGX sub-leafs.
iter(&self) -> SgxSectionIter3544     pub fn iter(&self) -> SgxSectionIter {
3545         SgxSectionIter { current: 2 }
3546     }
3547 }
3548 
3549 /// Iterator over the SGX sub-leafs (ECX >= 2).
3550 #[derive(Debug, Default)]
3551 #[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))]
3552 pub struct SgxSectionIter {
3553     current: u32,
3554 }
3555 
3556 impl Iterator for SgxSectionIter {
3557     type Item = SgxSectionInfo;
3558 
next(&mut self) -> Option<SgxSectionInfo>3559     fn next(&mut self) -> Option<SgxSectionInfo> {
3560         self.current += 1;
3561         let res = cpuid!(EAX_SGX, self.current);
3562         match get_bits(res.eax, 0, 3) {
3563             0b0001 => Some(SgxSectionInfo::Epc(EpcSection {
3564                 eax: res.eax,
3565                 ebx: res.ebx,
3566                 ecx: res.ecx,
3567                 edx: res.edx,
3568             })),
3569             _ => None,
3570         }
3571     }
3572 }
3573 
3574 /// Intel SGX EPC Enumeration Leaf, sub-leaves (EAX = 12H, ECX = 2 or higher)
3575 #[derive(Debug)]
3576 #[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))]
3577 pub enum SgxSectionInfo {
3578     // This would be nice: https://github.com/rust-lang/rfcs/pull/1450
3579     Epc(EpcSection),
3580 }
3581 
3582 impl Default for SgxSectionInfo {
default() -> SgxSectionInfo3583     fn default() -> SgxSectionInfo {
3584         SgxSectionInfo::Epc(Default::default())
3585     }
3586 }
3587 
3588 /// EBX:EAX and EDX:ECX provide information on the Enclave Page Cache (EPC) section
3589 #[derive(Debug, Default)]
3590 #[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))]
3591 pub struct EpcSection {
3592     eax: u32,
3593     ebx: u32,
3594     ecx: u32,
3595     edx: u32,
3596 }
3597 
3598 impl EpcSection {
3599     /// The physical address of the base of the EPC section
physical_base(&self) -> u643600     pub fn physical_base(&self) -> u64 {
3601         let lower = (get_bits(self.eax, 12, 31) << 12) as u64;
3602         let upper = (get_bits(self.ebx, 0, 19) as u64) << 32;
3603         lower | upper
3604     }
3605 
3606     /// Size of the corresponding EPC section within the Processor Reserved Memory.
size(&self) -> u643607     pub fn size(&self) -> u64 {
3608         let lower = (get_bits(self.ecx, 12, 31) << 12) as u64;
3609         let upper = (get_bits(self.edx, 0, 19) as u64) << 32;
3610         lower | upper
3611     }
3612 }
3613 
3614 #[derive(Debug, Default)]
3615 #[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))]
3616 pub struct ProcessorTraceInfo {
3617     eax: u32,
3618     ebx: u32,
3619     ecx: u32,
3620     edx: u32,
3621     leaf1: Option<CpuIdResult>,
3622 }
3623 
3624 impl ProcessorTraceInfo {
3625     // EBX features
3626     check_bit_fn!(
3627         doc = "If true, Indicates that IA32_RTIT_CTL.CR3Filter can be set to 1, and \
3628                that IA32_RTIT_CR3_MATCH MSR can be accessed.",
3629         has_rtit_cr3_match,
3630         ebx,
3631         0
3632     );
3633     check_bit_fn!(
3634         doc = "If true, Indicates support of Configurable PSB and Cycle-Accurate Mode.",
3635         has_configurable_psb_and_cycle_accurate_mode,
3636         ebx,
3637         1
3638     );
3639     check_bit_fn!(
3640         doc = "If true, Indicates support of IP Filtering, TraceStop filtering, and \
3641                preservation of Intel PT MSRs across warm reset.",
3642         has_ip_tracestop_filtering,
3643         ebx,
3644         2
3645     );
3646     check_bit_fn!(
3647         doc = "If true, Indicates support of MTC timing packet and suppression of \
3648                COFI-based packets.",
3649         has_mtc_timing_packet_coefi_suppression,
3650         ebx,
3651         3
3652     );
3653 
3654     check_bit_fn!(
3655         doc = "Indicates support of PTWRITE. Writes can set IA32_RTIT_CTL\\[12\\] (PTWEn \
3656                and IA32_RTIT_CTL\\[5\\] (FUPonPTW), and PTWRITE can generate packets",
3657         has_ptwrite,
3658         ebx,
3659         4
3660     );
3661 
3662     check_bit_fn!(
3663         doc = "Support of Power Event Trace. Writes can set IA32_RTIT_CTL\\[4\\] (PwrEvtEn) \
3664                enabling Power Event Trace packet generation.",
3665         has_power_event_trace,
3666         ebx,
3667         5
3668     );
3669 
3670     // ECX features
3671     check_bit_fn!(
3672         doc = "If true, Tracing can be enabled with IA32_RTIT_CTL.ToPA = 1, hence \
3673                utilizing the ToPA output scheme; IA32_RTIT_OUTPUT_BASE and \
3674                IA32_RTIT_OUTPUT_MASK_PTRS MSRs can be accessed.",
3675         has_topa,
3676         ecx,
3677         0
3678     );
3679     check_bit_fn!(
3680         doc = "If true, ToPA tables can hold any number of output entries, up to the \
3681                maximum allowed by the MaskOrTableOffset field of \
3682                IA32_RTIT_OUTPUT_MASK_PTRS.",
3683         has_topa_maximum_entries,
3684         ecx,
3685         1
3686     );
3687     check_bit_fn!(
3688         doc = "If true, Indicates support of Single-Range Output scheme.",
3689         has_single_range_output_scheme,
3690         ecx,
3691         2
3692     );
3693     check_bit_fn!(
3694         doc = "If true, Indicates support of output to Trace Transport subsystem.",
3695         has_trace_transport_subsystem,
3696         ecx,
3697         3
3698     );
3699     check_bit_fn!(
3700         doc = "If true, Generated packets which contain IP payloads have LIP values, \
3701                which include the CS base component.",
3702         has_lip_with_cs_base,
3703         ecx,
3704         31
3705     );
3706 
3707     /// Number of configurable Address Ranges for filtering (Bits 2:0).
configurable_address_ranges(&self) -> u83708     pub fn configurable_address_ranges(&self) -> u8 {
3709         self.leaf1.map_or(0, |res| get_bits(res.eax, 0, 2) as u8)
3710     }
3711 
3712     /// Bitmap of supported MTC period encodings (Bit 31:16).
supported_mtc_period_encodings(&self) -> u163713     pub fn supported_mtc_period_encodings(&self) -> u16 {
3714         self.leaf1.map_or(0, |res| get_bits(res.eax, 16, 31) as u16)
3715     }
3716 
3717     /// Bitmap of supported Cycle Threshold value encodings (Bits 15-0).
supported_cycle_threshold_value_encodings(&self) -> u163718     pub fn supported_cycle_threshold_value_encodings(&self) -> u16 {
3719         self.leaf1.map_or(0, |res| get_bits(res.ebx, 0, 15) as u16)
3720     }
3721 
3722     /// Bitmap of supported Configurable PSB frequency encodings (Bit 31:16)
supported_psb_frequency_encodings(&self) -> u163723     pub fn supported_psb_frequency_encodings(&self) -> u16 {
3724         self.leaf1.map_or(0, |res| get_bits(res.ebx, 16, 31) as u16)
3725     }
3726 }
3727 
3728 /// Time Stamp Counter and Nominal Core Crystal Clock Information Leaf.
3729 #[derive(Default)]
3730 #[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))]
3731 pub struct TscInfo {
3732     eax: u32,
3733     ebx: u32,
3734     ecx: u32,
3735 }
3736 
3737 impl fmt::Debug for TscInfo {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result3738     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
3739         f.debug_struct("TscInfo")
3740             .field("denominator/eax", &self.denominator())
3741             .field("numerator/ebx", &self.numerator())
3742             .field("nominal_frequency/ecx", &self.nominal_frequency())
3743             .finish()
3744     }
3745 }
3746 
3747 impl TscInfo {
3748     /// An unsigned integer which is the denominator of the TSC/”core crystal clock” ratio.
denominator(&self) -> u323749     pub fn denominator(&self) -> u32 {
3750         self.eax
3751     }
3752 
3753     /// An unsigned integer which is the numerator of the TSC/”core crystal clock” ratio.
3754     ///
3755     /// If this is 0, the TSC/”core crystal clock” ratio is not enumerated.
numerator(&self) -> u323756     pub fn numerator(&self) -> u32 {
3757         self.ebx
3758     }
3759 
3760     /// An unsigned integer which is the nominal frequency of the core crystal clock in Hz.
3761     ///
3762     /// If this is 0, the nominal core crystal clock frequency is not enumerated.
nominal_frequency(&self) -> u323763     pub fn nominal_frequency(&self) -> u32 {
3764         self.ecx
3765     }
3766 
3767     /// “TSC frequency” = “core crystal clock frequency” * EBX/EAX.
tsc_frequency(&self) -> u643768     pub fn tsc_frequency(&self) -> u64 {
3769         self.nominal_frequency() as u64 * self.numerator() as u64 / self.denominator() as u64
3770     }
3771 }
3772 
3773 /// Processor Frequency Information
3774 #[derive(Debug, Default)]
3775 #[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))]
3776 pub struct ProcessorFrequencyInfo {
3777     eax: u32,
3778     ebx: u32,
3779     ecx: u32,
3780 }
3781 
3782 impl ProcessorFrequencyInfo {
3783     /// Processor Base Frequency (in MHz).
processor_base_frequency(&self) -> u163784     pub fn processor_base_frequency(&self) -> u16 {
3785         get_bits(self.eax, 0, 15) as u16
3786     }
3787 
3788     /// Maximum Frequency (in MHz).
processor_max_frequency(&self) -> u163789     pub fn processor_max_frequency(&self) -> u16 {
3790         get_bits(self.ebx, 0, 15) as u16
3791     }
3792 
3793     /// Bus (Reference) Frequency (in MHz).
bus_frequency(&self) -> u163794     pub fn bus_frequency(&self) -> u16 {
3795         get_bits(self.ecx, 0, 15) as u16
3796     }
3797 }
3798 
3799 /// Deterministic Address Translation Structure Iterator
3800 #[derive(Debug, Default)]
3801 #[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))]
3802 pub struct DatIter {
3803     current: u32,
3804     count: u32,
3805 }
3806 
3807 impl Iterator for DatIter {
3808     type Item = DatInfo;
3809 
3810     /// Iterate over each sub-leaf with an  address translation structure.
next(&mut self) -> Option<DatInfo>3811     fn next(&mut self) -> Option<DatInfo> {
3812         loop {
3813             // Sub-leaf index n is invalid if n exceeds the value that sub-leaf 0 returns in EAX
3814             if self.current > self.count {
3815                 return None;
3816             }
3817 
3818             let res = cpuid!(EAX_DETERMINISTIC_ADDRESS_TRANSLATION_INFO, self.current);
3819             self.current += 1;
3820 
3821             // A sub-leaf index is also invalid if EDX[4:0] returns 0.
3822             if get_bits(res.edx, 0, 4) == 0 {
3823                 // Valid sub-leaves do not need to be contiguous or in any particular order.
3824                 // A valid sub-leaf may be in a higher input ECX value than an invalid sub-leaf
3825                 // or than a valid sub-leaf of a higher or lower-level struc-ture
3826                 continue;
3827             }
3828 
3829             return Some(DatInfo {
3830                 eax: res.eax,
3831                 ebx: res.ebx,
3832                 ecx: res.ecx,
3833                 edx: res.edx,
3834             });
3835         }
3836     }
3837 }
3838 
3839 /// Deterministic Address Translation Structure
3840 #[derive(Debug, Default)]
3841 #[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))]
3842 pub struct DatInfo {
3843     eax: u32,
3844     ebx: u32,
3845     ecx: u32,
3846     edx: u32,
3847 }
3848 
3849 impl DatInfo {
3850     check_bit_fn!(
3851         doc = "4K page size entries supported by this structure",
3852         has_4k_entries,
3853         ebx,
3854         0
3855     );
3856 
3857     check_bit_fn!(
3858         doc = "2MB page size entries supported by this structure",
3859         has_2mb_entries,
3860         ebx,
3861         1
3862     );
3863 
3864     check_bit_fn!(
3865         doc = "4MB page size entries supported by this structure",
3866         has_4mb_entries,
3867         ebx,
3868         2
3869     );
3870 
3871     check_bit_fn!(
3872         doc = "1GB page size entries supported by this structure",
3873         has_1gb_entries,
3874         ebx,
3875         3
3876     );
3877 
3878     check_bit_fn!(
3879         doc = "Fully associative structure",
3880         is_fully_associative,
3881         edx,
3882         8
3883     );
3884 
3885     /// Partitioning (0: Soft partitioning between the logical processors sharing this structure).
partitioning(&self) -> u83886     pub fn partitioning(&self) -> u8 {
3887         get_bits(self.ebx, 8, 10) as u8
3888     }
3889 
3890     /// Ways of associativity.
ways(&self) -> u163891     pub fn ways(&self) -> u16 {
3892         get_bits(self.ebx, 16, 31) as u16
3893     }
3894 
3895     /// Number of Sets.
sets(&self) -> u323896     pub fn sets(&self) -> u32 {
3897         self.ecx
3898     }
3899 
3900     /// Translation cache type field.
cache_type(&self) -> DatType3901     pub fn cache_type(&self) -> DatType {
3902         match get_bits(self.edx, 0, 4) as u8 {
3903             0b00001 => DatType::DataTLB,
3904             0b00010 => DatType::InstructionTLB,
3905             0b00011 => DatType::UnifiedTLB,
3906             0b00000 => DatType::Null, // should never be returned as this indicates invalid struct!
3907             _ => DatType::Unknown,
3908         }
3909     }
3910 
3911     /// Translation cache level (starts at 1)
cache_level(&self) -> u83912     pub fn cache_level(&self) -> u8 {
3913         get_bits(self.edx, 5, 7) as u8
3914     }
3915 
3916     /// Maximum number of addressable IDs for logical processors sharing this translation cache
max_addressable_ids(&self) -> u163917     pub fn max_addressable_ids(&self) -> u16 {
3918         // Add one to the return value to get the result:
3919         (get_bits(self.edx, 14, 25) + 1) as u16
3920     }
3921 }
3922 
3923 /// Deterministic Address Translation cache type (EDX bits 04 -- 00)
3924 #[derive(Debug)]
3925 #[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))]
3926 pub enum DatType {
3927     /// Null (indicates this sub-leaf is not valid).
3928     Null = 0b00000,
3929     DataTLB = 0b00001,
3930     InstructionTLB = 0b00010,
3931     /// Some unified TLBs will allow a single TLB entry to satisfy data read/write
3932     /// and instruction fetches. Others will require separate entries (e.g., one
3933     /// loaded on data read/write and another loaded on an instruction fetch) .
3934     /// Please see the Intel® 64 and IA-32 Architectures Optimization Reference Manual
3935     /// for details of a particular product.
3936     UnifiedTLB = 0b00011,
3937     Unknown,
3938 }
3939 
3940 impl Default for DatType {
default() -> DatType3941     fn default() -> DatType {
3942         DatType::Null
3943     }
3944 }
3945 
3946 #[derive(Debug, Default)]
3947 #[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))]
3948 pub struct SoCVendorInfo {
3949     /// MaxSOCID_Index
3950     eax: u32,
3951     ebx: u32,
3952     ecx: u32,
3953     edx: u32,
3954 }
3955 
3956 impl SoCVendorInfo {
get_soc_vendor_id(&self) -> u163957     pub fn get_soc_vendor_id(&self) -> u16 {
3958         get_bits(self.ebx, 0, 15) as u16
3959     }
3960 
get_project_id(&self) -> u323961     pub fn get_project_id(&self) -> u32 {
3962         self.ecx
3963     }
3964 
get_stepping_id(&self) -> u323965     pub fn get_stepping_id(&self) -> u32 {
3966         self.edx
3967     }
3968 
get_vendor_brand(&self) -> SoCVendorBrand3969     pub fn get_vendor_brand(&self) -> SoCVendorBrand {
3970         assert!(self.eax >= 3); // Leaf 17H is valid if MaxSOCID_Index >= 3.
3971         let r1 = cpuid!(EAX_SOC_VENDOR_INFO, 1);
3972         let r2 = cpuid!(EAX_SOC_VENDOR_INFO, 2);
3973         let r3 = cpuid!(EAX_SOC_VENDOR_INFO, 3);
3974         SoCVendorBrand { data: [r1, r2, r3] }
3975     }
3976 
get_vendor_attributes(&self) -> Option<SoCVendorAttributesIter>3977     pub fn get_vendor_attributes(&self) -> Option<SoCVendorAttributesIter> {
3978         if self.eax > 3 {
3979             Some(SoCVendorAttributesIter {
3980                 count: self.eax,
3981                 current: 3,
3982             })
3983         } else {
3984             None
3985         }
3986     }
3987 }
3988 
3989 #[derive(Debug, Default)]
3990 #[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))]
3991 pub struct SoCVendorAttributesIter {
3992     count: u32,
3993     current: u32,
3994 }
3995 
3996 impl Iterator for SoCVendorAttributesIter {
3997     type Item = CpuIdResult;
3998 
3999     /// Iterate over all SoC vendor specific attributes.
next(&mut self) -> Option<CpuIdResult>4000     fn next(&mut self) -> Option<CpuIdResult> {
4001         if self.current > self.count {
4002             return None;
4003         }
4004         self.count += 1;
4005         Some(cpuid!(EAX_SOC_VENDOR_INFO, self.count))
4006     }
4007 }
4008 
4009 #[derive(Debug, Default)]
4010 #[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))]
4011 pub struct SoCVendorBrand {
4012     #[allow(dead_code)]
4013     data: [CpuIdResult; 3],
4014 }
4015 
4016 impl SoCVendorBrand {
as_string<'a>(&'a self) -> &'a str4017     pub fn as_string<'a>(&'a self) -> &'a str {
4018         unsafe {
4019             let brand_string_start = self as *const SoCVendorBrand as *const u8;
4020             let slice =
4021                 slice::from_raw_parts(brand_string_start, core::mem::size_of::<SoCVendorBrand>());
4022             let byte_array: &'a [u8] = transmute(slice);
4023             str::from_utf8_unchecked(byte_array)
4024         }
4025     }
4026 }
4027 
4028 impl fmt::Display for SoCVendorBrand {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result4029     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
4030         write!(f, "{}", self.as_string())
4031     }
4032 }
4033 
4034 /// Information about Hypervisor (https://lwn.net/Articles/301888/)
4035 pub struct HypervisorInfo {
4036     res: CpuIdResult,
4037 }
4038 
4039 impl fmt::Debug for HypervisorInfo {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result4040     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
4041         f.debug_struct("HypervisorInfo")
4042             .field("type", &self.identify())
4043             .field("tsc_frequency", &self.tsc_frequency())
4044             .field("apic_frequency", &self.apic_frequency())
4045             .finish()
4046     }
4047 }
4048 
4049 /// Identifies the different Hypervisor products.
4050 #[derive(Debug, Eq, PartialEq)]
4051 pub enum Hypervisor {
4052     Xen,
4053     VMware,
4054     HyperV,
4055     KVM,
4056     Unknown(u32, u32, u32),
4057 }
4058 
4059 impl HypervisorInfo {
identify(&self) -> Hypervisor4060     pub fn identify(&self) -> Hypervisor {
4061         match (self.res.ebx, self.res.ecx, self.res.edx) {
4062             // "VMwareVMware"
4063             (0x61774d56, 0x4d566572, 0x65726177) => Hypervisor::VMware,
4064             // "XenVMMXenVMM"
4065             (0x566e6558, 0x65584d4d, 0x4d4d566e) => Hypervisor::Xen,
4066             // "Microsoft Hv"
4067             (0x7263694d, 0x666f736f, 0x76482074) => Hypervisor::HyperV,
4068             // "KVMKVMKVM\0\0\0"
4069             (0x4b4d564b, 0x564b4d56, 0x0000004d) => Hypervisor::KVM,
4070             (ebx, ecx, edx) => Hypervisor::Unknown(ebx, ecx, edx),
4071         }
4072     }
4073 
4074     /// TSC frequency in kHz.
tsc_frequency(&self) -> Option<u32>4075     pub fn tsc_frequency(&self) -> Option<u32> {
4076         // vm aware tsc frequency retrieval:
4077         // # EAX: (Virtual) TSC frequency in kHz.
4078         if self.res.eax >= 0x40000010 {
4079             let virt_tinfo = cpuid!(0x40000010, 0);
4080             Some(virt_tinfo.eax)
4081         } else {
4082             None
4083         }
4084     }
4085 
4086     /// (Virtual) Bus (local apic timer) frequency in kHz.
apic_frequency(&self) -> Option<u32>4087     pub fn apic_frequency(&self) -> Option<u32> {
4088         // # EBX: (Virtual) Bus (local apic timer) frequency in kHz.
4089         if self.res.eax >= 0x40000010 {
4090             let virt_tinfo = cpuid!(0x40000010, 0);
4091             Some(virt_tinfo.ebx)
4092         } else {
4093             None
4094         }
4095     }
4096 }
4097 
4098 #[derive(Debug, Default)]
4099 #[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))]
4100 pub struct ExtendedFunctionInfo {
4101     max_eax_value: u32,
4102     data: [CpuIdResult; 9],
4103 }
4104 
4105 #[derive(PartialEq, Eq, Debug)]
4106 #[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))]
4107 pub enum L2Associativity {
4108     Disabled = 0x0,
4109     DirectMapped = 0x1,
4110     TwoWay = 0x2,
4111     FourWay = 0x4,
4112     EightWay = 0x6,
4113     SixteenWay = 0x8,
4114     FullyAssiciative = 0xF,
4115     Unknown,
4116 }
4117 
4118 impl Default for L2Associativity {
default() -> L2Associativity4119     fn default() -> L2Associativity {
4120         L2Associativity::Unknown
4121     }
4122 }
4123 
4124 const EAX_EXTENDED_PROC_SIGNATURE: u32 = 0x1;
4125 const EAX_EXTENDED_BRAND_STRING: u32 = 0x4;
4126 const EAX_EXTENDED_CACHE_INFO: u32 = 0x6;
4127 
4128 impl ExtendedFunctionInfo {
leaf_is_supported(&self, val: u32) -> bool4129     fn leaf_is_supported(&self, val: u32) -> bool {
4130         val <= self.max_eax_value
4131     }
4132 
4133     /// Retrieve processor brand string.
processor_brand_string<'a>(&'a self) -> Option<&'a str>4134     pub fn processor_brand_string<'a>(&'a self) -> Option<&'a str> {
4135         if self.leaf_is_supported(EAX_EXTENDED_BRAND_STRING) {
4136             Some(unsafe {
4137                 let brand_string_start = &self.data[2] as *const CpuIdResult as *const u8;
4138                 let mut slice = slice::from_raw_parts(brand_string_start, 3 * 4 * 4);
4139 
4140                 match slice.iter().position(|&x| x == 0) {
4141                     Some(index) => slice = slice::from_raw_parts(brand_string_start, index),
4142                     None => (),
4143                 }
4144 
4145                 let byte_array: &'a [u8] = transmute(slice);
4146                 str::from_utf8_unchecked(byte_array)
4147             })
4148         } else {
4149             None
4150         }
4151     }
4152 
4153     /// Extended Processor Signature and Feature Bits.
extended_signature(&self) -> Option<u32>4154     pub fn extended_signature(&self) -> Option<u32> {
4155         if self.leaf_is_supported(EAX_EXTENDED_PROC_SIGNATURE) {
4156             Some(self.data[1].eax)
4157         } else {
4158             None
4159         }
4160     }
4161 
4162     /// Cache Line size in bytes
cache_line_size(&self) -> Option<u8>4163     pub fn cache_line_size(&self) -> Option<u8> {
4164         if self.leaf_is_supported(EAX_EXTENDED_CACHE_INFO) {
4165             Some(get_bits(self.data[6].ecx, 0, 7) as u8)
4166         } else {
4167             None
4168         }
4169     }
4170 
4171     /// L2 Associativity field
l2_associativity(&self) -> Option<L2Associativity>4172     pub fn l2_associativity(&self) -> Option<L2Associativity> {
4173         if self.leaf_is_supported(EAX_EXTENDED_CACHE_INFO) {
4174             Some(match get_bits(self.data[6].ecx, 12, 15) {
4175                 0x0 => L2Associativity::Disabled,
4176                 0x1 => L2Associativity::DirectMapped,
4177                 0x2 => L2Associativity::TwoWay,
4178                 0x4 => L2Associativity::FourWay,
4179                 0x6 => L2Associativity::EightWay,
4180                 0x8 => L2Associativity::SixteenWay,
4181                 0xF => L2Associativity::FullyAssiciative,
4182                 _ => L2Associativity::Unknown,
4183             })
4184         } else {
4185             None
4186         }
4187     }
4188 
4189     /// Cache size in 1K units
cache_size(&self) -> Option<u16>4190     pub fn cache_size(&self) -> Option<u16> {
4191         if self.leaf_is_supported(EAX_EXTENDED_CACHE_INFO) {
4192             Some(get_bits(self.data[6].ecx, 16, 31) as u16)
4193         } else {
4194             None
4195         }
4196     }
4197 
4198     /// #Physical Address Bits
physical_address_bits(&self) -> Option<u8>4199     pub fn physical_address_bits(&self) -> Option<u8> {
4200         if self.leaf_is_supported(8) {
4201             Some(get_bits(self.data[8].eax, 0, 7) as u8)
4202         } else {
4203             None
4204         }
4205     }
4206 
4207     /// #Linear Address Bits
linear_address_bits(&self) -> Option<u8>4208     pub fn linear_address_bits(&self) -> Option<u8> {
4209         if self.leaf_is_supported(8) {
4210             Some(get_bits(self.data[8].eax, 8, 15) as u8)
4211         } else {
4212             None
4213         }
4214     }
4215 
4216     /// Is Invariant TSC available?
has_invariant_tsc(&self) -> bool4217     pub fn has_invariant_tsc(&self) -> bool {
4218         self.leaf_is_supported(7) && self.data[7].edx & (1 << 8) > 0
4219     }
4220 
4221     /// Is LAHF/SAHF available in 64-bit mode?
has_lahf_sahf(&self) -> bool4222     pub fn has_lahf_sahf(&self) -> bool {
4223         self.leaf_is_supported(1)
4224             && ExtendedFunctionInfoEcx {
4225                 bits: self.data[1].ecx,
4226             }
4227             .contains(ExtendedFunctionInfoEcx::LAHF_SAHF)
4228     }
4229 
4230     /// Is LZCNT available?
has_lzcnt(&self) -> bool4231     pub fn has_lzcnt(&self) -> bool {
4232         self.leaf_is_supported(1)
4233             && ExtendedFunctionInfoEcx {
4234                 bits: self.data[1].ecx,
4235             }
4236             .contains(ExtendedFunctionInfoEcx::LZCNT)
4237     }
4238 
4239     /// Is PREFETCHW available?
has_prefetchw(&self) -> bool4240     pub fn has_prefetchw(&self) -> bool {
4241         self.leaf_is_supported(1)
4242             && ExtendedFunctionInfoEcx {
4243                 bits: self.data[1].ecx,
4244             }
4245             .contains(ExtendedFunctionInfoEcx::PREFETCHW)
4246     }
4247 
4248     /// Are fast system calls available.
has_syscall_sysret(&self) -> bool4249     pub fn has_syscall_sysret(&self) -> bool {
4250         self.leaf_is_supported(1)
4251             && ExtendedFunctionInfoEdx {
4252                 bits: self.data[1].edx,
4253             }
4254             .contains(ExtendedFunctionInfoEdx::SYSCALL_SYSRET)
4255     }
4256 
4257     /// Is there support for execute disable bit.
has_execute_disable(&self) -> bool4258     pub fn has_execute_disable(&self) -> bool {
4259         self.leaf_is_supported(1)
4260             && ExtendedFunctionInfoEdx {
4261                 bits: self.data[1].edx,
4262             }
4263             .contains(ExtendedFunctionInfoEdx::EXECUTE_DISABLE)
4264     }
4265 
4266     /// Is there support for 1GiB pages.
has_1gib_pages(&self) -> bool4267     pub fn has_1gib_pages(&self) -> bool {
4268         self.leaf_is_supported(1)
4269             && ExtendedFunctionInfoEdx {
4270                 bits: self.data[1].edx,
4271             }
4272             .contains(ExtendedFunctionInfoEdx::GIB_PAGES)
4273     }
4274 
4275     /// Check support for rdtscp instruction.
has_rdtscp(&self) -> bool4276     pub fn has_rdtscp(&self) -> bool {
4277         self.leaf_is_supported(1)
4278             && ExtendedFunctionInfoEdx {
4279                 bits: self.data[1].edx,
4280             }
4281             .contains(ExtendedFunctionInfoEdx::RDTSCP)
4282     }
4283 
4284     /// Check support for 64-bit mode.
has_64bit_mode(&self) -> bool4285     pub fn has_64bit_mode(&self) -> bool {
4286         self.leaf_is_supported(1)
4287             && ExtendedFunctionInfoEdx {
4288                 bits: self.data[1].edx,
4289             }
4290             .contains(ExtendedFunctionInfoEdx::I64BIT_MODE)
4291     }
4292 }
4293 
4294 bitflags! {
4295     #[derive(Default)]
4296     #[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))]
4297     struct ExtendedFunctionInfoEcx: u32 {
4298         /// LAHF/SAHF available in 64-bit mode.
4299         const LAHF_SAHF = 1 << 0;
4300         /// Bit 05: LZCNT
4301         const LZCNT = 1 << 5;
4302         /// Bit 08: PREFETCHW
4303         const PREFETCHW = 1 << 8;
4304     }
4305 }
4306 
4307 bitflags! {
4308     #[derive(Default)]
4309     #[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))]
4310     struct ExtendedFunctionInfoEdx: u32 {
4311         /// SYSCALL/SYSRET available in 64-bit mode (Bit 11).
4312         const SYSCALL_SYSRET = 1 << 11;
4313         /// Execute Disable Bit available (Bit 20).
4314         const EXECUTE_DISABLE = 1 << 20;
4315         /// 1-GByte pages are available if 1 (Bit 26).
4316         const GIB_PAGES = 1 << 26;
4317         /// RDTSCP and IA32_TSC_AUX are available if 1 (Bit 27).
4318         const RDTSCP = 1 << 27;
4319         /// Intel ® 64 Architecture available if 1 (Bit 29).
4320         const I64BIT_MODE = 1 << 29;
4321     }
4322 }
4323 
4324 #[derive(Debug, Default)]
4325 #[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))]
4326 pub struct MemoryEncryptionInfo {
4327     eax: MemoryEncryptionInfoEax,
4328     ebx: u32,
4329     ecx: u32,
4330     edx: u32,
4331 }
4332 
4333 impl MemoryEncryptionInfo {
4334     check_flag!(
4335         doc = "Secure Memory Encryption is supported if set.",
4336         has_sme,
4337         eax,
4338         MemoryEncryptionInfoEax::SME
4339     );
4340 
4341     check_flag!(
4342         doc = "Secure Encrypted Virtualization is supported if set.",
4343         has_sev,
4344         eax,
4345         MemoryEncryptionInfoEax::SEV
4346     );
4347 
4348     check_flag!(
4349         doc = "The Page Flush MSR is available if set.",
4350         has_page_flush_msr,
4351         eax,
4352         MemoryEncryptionInfoEax::PAGE_FLUSH_MSR
4353     );
4354 
4355     check_flag!(
4356         doc = "SEV Encrypted State is supported if set.",
4357         has_sev_es,
4358         eax,
4359         MemoryEncryptionInfoEax::SEV_ES
4360     );
4361 
physical_address_reduction(&self) -> u84362     pub fn physical_address_reduction(&self) -> u8 {
4363         get_bits(self.ebx, 6, 11) as u8
4364     }
4365 
c_bit_position(&self) -> u84366     pub fn c_bit_position(&self) -> u8 {
4367         get_bits(self.ebx, 0, 5) as u8
4368     }
4369 
max_encrypted_guests(&self) -> u324370     pub fn max_encrypted_guests(&self) -> u32 {
4371         self.ecx
4372     }
4373 
min_sev_no_es_asid(&self) -> u324374     pub fn min_sev_no_es_asid(&self) -> u32 {
4375         self.edx
4376     }
4377 }
4378 
4379 bitflags! {
4380     #[derive(Default)]
4381     #[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))]
4382     struct MemoryEncryptionInfoEax: u32 {
4383         /// Bit 00: SME supported
4384         const SME = 1 << 0;
4385         /// Bit 01: SEV supported
4386         const SEV = 1 << 1;
4387         /// Bit 02: Page Flush MSR available
4388         const PAGE_FLUSH_MSR = 1 << 2;
4389         /// Bit 03: SEV-ES supported
4390         const SEV_ES = 1 << 3;
4391     }
4392 }
4393