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