raw_cpuid/
lib.rs

1//! A library to parse the x86 CPUID instruction, written in rust with no
2//! external dependencies. The implementation closely resembles the Intel CPUID
3//! manual description. The library works with no_std.
4//!
5//! ## Example
6//! ```rust
7//! use raw_cpuid::CpuId;
8//! let cpuid = CpuId::new();
9//!
10//! if let Some(vf) = cpuid.get_vendor_info() {
11//!     assert!(vf.as_str() == "GenuineIntel" || vf.as_str() == "AuthenticAMD");
12//! }
13//!
14//! let has_sse = cpuid.get_feature_info().map_or(false, |finfo| finfo.has_sse());
15//! if has_sse {
16//!     println!("CPU supports SSE!");
17//! }
18//!
19//! if let Some(cparams) = cpuid.get_cache_parameters() {
20//!     for cache in cparams {
21//!         let size = cache.associativity() * cache.physical_line_partitions() * cache.coherency_line_size() * cache.sets();
22//!         println!("L{}-Cache size is {}", cache.level(), size);
23//!     }
24//! } else {
25//!     println!("No cache parameter information available")
26//! }
27//! ```
28//!
29//! # Platform support
30//!
31//! CPU vendors may choose to not support certain functions/leafs in cpuid or
32//! only support them partially. We highlight this with the following emojis
33//! throughout the documentation:
34//!
35//! - ✅: This struct/function is fully supported by the vendor.
36//! - 🟡: This struct is partially supported by the vendor, refer to individual
37//!   functions for more information.
38//! - ❌: This struct/function is not supported by the vendor. When queried on
39//!   this platform, we will return None/false/0 (or some other sane default).
40//! - ❓: This struct/function is not supported by the vendor according to the
41//!   manual, but the in practice it still may return valid information.
42//!
43//! Note that the presence of a ✅ does not guarantee that a specific feature
44//! will exist for your CPU -- just that it is potentially supported by the
45//! vendor on some of its chips. You will still have to query it at runtime.
46
47#![cfg_attr(not(feature = "std"), no_std)]
48#![crate_name = "raw_cpuid"]
49#![crate_type = "lib"]
50
51#[cfg(test)]
52#[macro_use]
53extern crate std;
54
55#[cfg(feature = "display")]
56pub mod display;
57mod extended;
58#[cfg(test)]
59mod tests;
60
61use bitflags::bitflags;
62use core::fmt::{self, Debug, Formatter};
63use core::mem::size_of;
64use core::slice;
65use core::str;
66
67#[cfg(feature = "serialize")]
68use serde_derive::{Deserialize, Serialize};
69
70pub use extended::*;
71
72/// Uses Rust's `cpuid` function from the `arch` module.
73#[cfg(any(
74    all(target_arch = "x86", not(target_env = "sgx"), target_feature = "sse"),
75    all(target_arch = "x86_64", not(target_env = "sgx"))
76))]
77pub mod native_cpuid {
78    use crate::CpuIdResult;
79
80    #[cfg(all(target_arch = "x86", not(target_env = "sgx"), target_feature = "sse"))]
81    use core::arch::x86 as arch;
82    #[cfg(all(target_arch = "x86_64", not(target_env = "sgx")))]
83    use core::arch::x86_64 as arch;
84
85    pub fn cpuid_count(a: u32, c: u32) -> CpuIdResult {
86        // Safety: CPUID is supported on all x86_64 CPUs and all x86 CPUs with
87        // SSE, but not by SGX.
88        let result = unsafe { self::arch::__cpuid_count(a, c) };
89
90        CpuIdResult {
91            eax: result.eax,
92            ebx: result.ebx,
93            ecx: result.ecx,
94            edx: result.edx,
95        }
96    }
97    /// The native reader uses the cpuid instruction to read the cpuid data from the
98    /// CPU we're currently running on directly.
99    #[derive(Clone, Copy)]
100    pub struct CpuIdReaderNative;
101
102    impl super::CpuIdReader for CpuIdReaderNative {
103        fn cpuid2(&self, eax: u32, ecx: u32) -> CpuIdResult {
104            cpuid_count(eax, ecx)
105        }
106    }
107}
108
109#[cfg(any(
110    all(target_arch = "x86", not(target_env = "sgx"), target_feature = "sse"),
111    all(target_arch = "x86_64", not(target_env = "sgx"))
112))]
113pub use native_cpuid::CpuIdReaderNative;
114
115/// Macro which queries cpuid directly.
116///
117/// First parameter is cpuid leaf (EAX register value),
118/// second optional parameter is the subleaf (ECX register value).
119#[cfg(any(
120    all(target_arch = "x86", not(target_env = "sgx"), target_feature = "sse"),
121    all(target_arch = "x86_64", not(target_env = "sgx"))
122))]
123#[macro_export]
124macro_rules! cpuid {
125    ($eax:expr) => {
126        $crate::native_cpuid::cpuid_count($eax as u32, 0)
127    };
128
129    ($eax:expr, $ecx:expr) => {
130        $crate::native_cpuid::cpuid_count($eax as u32, $ecx as u32)
131    };
132}
133
134fn get_bits(r: u32, from: u32, to: u32) -> u32 {
135    assert!(from <= 31);
136    assert!(to <= 31);
137    assert!(from <= to);
138
139    let mask = match to {
140        31 => 0xffffffff,
141        _ => (1 << (to + 1)) - 1,
142    };
143
144    (r & mask) >> from
145}
146
147macro_rules! check_flag {
148    ($doc:meta, $fun:ident, $flags:ident, $flag:expr) => {
149        #[$doc]
150        pub fn $fun(&self) -> bool {
151            self.$flags.contains($flag)
152        }
153    };
154}
155
156macro_rules! is_bit_set {
157    ($field:expr, $bit:expr) => {
158        $field & (1 << $bit) > 0
159    };
160}
161
162macro_rules! check_bit_fn {
163    ($doc:meta, $fun:ident, $field:ident, $bit:expr) => {
164        #[$doc]
165        pub fn $fun(&self) -> bool {
166            is_bit_set!(self.$field, $bit)
167        }
168    };
169}
170
171/// Implements function to read/write cpuid.
172/// This allows to conveniently swap out the underlying cpuid implementation
173/// with one that returns data that is deterministic (for unit-testing).
174pub trait CpuIdReader: Clone {
175    fn cpuid1(&self, eax: u32) -> CpuIdResult {
176        self.cpuid2(eax, 0)
177    }
178    fn cpuid2(&self, eax: u32, ecx: u32) -> CpuIdResult;
179}
180
181impl<F> CpuIdReader for F
182where
183    F: Fn(u32, u32) -> CpuIdResult + Clone,
184{
185    fn cpuid2(&self, eax: u32, ecx: u32) -> CpuIdResult {
186        self(eax, ecx)
187    }
188}
189
190#[derive(Debug, Eq, PartialEq, Clone, Copy)]
191enum Vendor {
192    Intel,
193    Amd,
194    Unknown(u32, u32, u32),
195}
196
197impl Vendor {
198    fn from_vendor_leaf(res: CpuIdResult) -> Self {
199        let vi = VendorInfo {
200            ebx: res.ebx,
201            ecx: res.ecx,
202            edx: res.edx,
203        };
204
205        match vi.as_str() {
206            "GenuineIntel" => Vendor::Intel,
207            "AuthenticAMD" => Vendor::Amd,
208            _ => Vendor::Unknown(res.ebx, res.ecx, res.edx),
209        }
210    }
211}
212
213/// The main type used to query information about the CPU we're running on.
214///
215/// Other structs can be accessed by going through this type.
216#[derive(Clone, Copy)]
217pub struct CpuId<R: CpuIdReader> {
218    /// A generic reader to abstract the cpuid interface.
219    read: R,
220    /// CPU vendor to differentiate cases where logic needs to differ in code .
221    vendor: Vendor,
222    /// How many basic leafs are supported (EAX < EAX_HYPERVISOR_INFO)
223    supported_leafs: u32,
224    /// How many extended leafs are supported (e.g., leafs with EAX > EAX_EXTENDED_FUNCTION_INFO)
225    supported_extended_leafs: u32,
226}
227
228#[cfg(any(
229    all(target_arch = "x86", not(target_env = "sgx"), target_feature = "sse"),
230    all(target_arch = "x86_64", not(target_env = "sgx"))
231))]
232impl Default for CpuId<CpuIdReaderNative> {
233    /// Create a new `CpuId` instance.
234    fn default() -> Self {
235        CpuId::with_cpuid_fn(CpuIdReaderNative)
236    }
237}
238
239#[cfg(any(
240    all(target_arch = "x86", not(target_env = "sgx"), target_feature = "sse"),
241    all(target_arch = "x86_64", not(target_env = "sgx"))
242))]
243impl CpuId<CpuIdReaderNative> {
244    /// Create a new `CpuId` instance.
245    pub fn new() -> Self {
246        CpuId::default()
247    }
248}
249
250/// Low-level data-structure to store result of cpuid instruction.
251#[derive(Copy, Clone, Eq, PartialEq)]
252#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))]
253#[repr(C)]
254pub struct CpuIdResult {
255    /// Return value EAX register
256    pub eax: u32,
257    /// Return value EBX register
258    pub ebx: u32,
259    /// Return value ECX register
260    pub ecx: u32,
261    /// Return value EDX register
262    pub edx: u32,
263}
264
265impl CpuIdResult {
266    pub fn all_zero(&self) -> bool {
267        self.eax == 0 && self.ebx == 0 && self.ecx == 0 && self.edx == 0
268    }
269}
270
271impl Debug for CpuIdResult {
272    fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
273        f.debug_struct("CpuIdResult")
274            .field("eax", &(self.eax as *const u32))
275            .field("ebx", &(self.ebx as *const u32))
276            .field("ecx", &(self.ecx as *const u32))
277            .field("edx", &(self.edx as *const u32))
278            .finish()
279    }
280}
281
282//
283// Normal leafs:
284//
285const EAX_VENDOR_INFO: u32 = 0x0;
286const EAX_FEATURE_INFO: u32 = 0x1;
287const EAX_CACHE_INFO: u32 = 0x2;
288const EAX_PROCESSOR_SERIAL: u32 = 0x3;
289const EAX_CACHE_PARAMETERS: u32 = 0x4;
290const EAX_MONITOR_MWAIT_INFO: u32 = 0x5;
291const EAX_THERMAL_POWER_INFO: u32 = 0x6;
292const EAX_STRUCTURED_EXTENDED_FEATURE_INFO: u32 = 0x7;
293const EAX_DIRECT_CACHE_ACCESS_INFO: u32 = 0x9;
294const EAX_PERFORMANCE_MONITOR_INFO: u32 = 0xA;
295const EAX_EXTENDED_TOPOLOGY_INFO: u32 = 0xB;
296const EAX_EXTENDED_STATE_INFO: u32 = 0xD;
297const EAX_RDT_MONITORING: u32 = 0xF;
298const EAX_RDT_ALLOCATION: u32 = 0x10;
299const EAX_SGX: u32 = 0x12;
300const EAX_TRACE_INFO: u32 = 0x14;
301const EAX_TIME_STAMP_COUNTER_INFO: u32 = 0x15;
302const EAX_FREQUENCY_INFO: u32 = 0x16;
303const EAX_SOC_VENDOR_INFO: u32 = 0x17;
304const EAX_DETERMINISTIC_ADDRESS_TRANSLATION_INFO: u32 = 0x18;
305const EAX_EXTENDED_TOPOLOGY_INFO_V2: u32 = 0x1F;
306
307/// Hypervisor leaf
308const EAX_HYPERVISOR_INFO: u32 = 0x4000_0000;
309
310//
311// Extended leafs:
312//
313const EAX_EXTENDED_FUNCTION_INFO: u32 = 0x8000_0000;
314const EAX_EXTENDED_PROCESSOR_AND_FEATURE_IDENTIFIERS: u32 = 0x8000_0001;
315const EAX_EXTENDED_BRAND_STRING: u32 = 0x8000_0002;
316const EAX_L1_CACHE_INFO: u32 = 0x8000_0005;
317const EAX_L2_L3_CACHE_INFO: u32 = 0x8000_0006;
318const EAX_ADVANCED_POWER_MGMT_INFO: u32 = 0x8000_0007;
319const EAX_PROCESSOR_CAPACITY_INFO: u32 = 0x8000_0008;
320const EAX_TLB_1GB_PAGE_INFO: u32 = 0x8000_0019;
321const EAX_PERFORMANCE_OPTIMIZATION_INFO: u32 = 0x8000_001A;
322const EAX_CACHE_PARAMETERS_AMD: u32 = 0x8000_001D;
323const EAX_PROCESSOR_TOPOLOGY_INFO: u32 = 0x8000_001E;
324const EAX_MEMORY_ENCRYPTION_INFO: u32 = 0x8000_001F;
325const EAX_SVM_FEATURES: u32 = 0x8000_000A;
326
327impl<R: CpuIdReader> CpuId<R> {
328    /// Return new CpuId struct with custom reader function.
329    ///
330    /// This is useful for example when testing code or if we want to interpose
331    /// on the CPUID calls this library makes.
332    pub fn with_cpuid_reader(cpuid_fn: R) -> Self {
333        let vendor_leaf = cpuid_fn.cpuid1(EAX_VENDOR_INFO);
334        let extended_leaf = cpuid_fn.cpuid1(EAX_EXTENDED_FUNCTION_INFO);
335        CpuId {
336            supported_leafs: vendor_leaf.eax,
337            supported_extended_leafs: extended_leaf.eax,
338            vendor: Vendor::from_vendor_leaf(vendor_leaf),
339            read: cpuid_fn,
340        }
341    }
342
343    /// See [`CpuId::with_cpuid_reader`].
344    ///
345    /// # Note
346    /// This function will likely be deprecated in the future. Use the identical
347    /// `with_cpuid_reader` function instead.
348    pub fn with_cpuid_fn(cpuid_fn: R) -> Self {
349        CpuId::with_cpuid_reader(cpuid_fn)
350    }
351
352    /// Check if a non extended leaf  (`val`) is supported.
353    fn leaf_is_supported(&self, val: u32) -> bool {
354        // Exclude reserved functions/leafs on AMD
355        if self.vendor == Vendor::Amd && ((0x2..=0x4).contains(&val) || (0x8..=0xa).contains(&val))
356        {
357            return false;
358        }
359
360        if val < EAX_EXTENDED_FUNCTION_INFO {
361            val <= self.supported_leafs
362        } else {
363            val <= self.supported_extended_leafs
364        }
365    }
366
367    /// Return information about the vendor (LEAF=0x00).
368    ///
369    /// This leaf will contain a ASCII readable string such as "GenuineIntel"
370    /// for Intel CPUs or "AuthenticAMD" for AMD CPUs.
371    ///
372    /// # Platforms
373    /// ✅ AMD ✅ Intel
374    pub fn get_vendor_info(&self) -> Option<VendorInfo> {
375        if self.leaf_is_supported(EAX_VENDOR_INFO) {
376            let res = self.read.cpuid1(EAX_VENDOR_INFO);
377            Some(VendorInfo {
378                ebx: res.ebx,
379                ecx: res.ecx,
380                edx: res.edx,
381            })
382        } else {
383            None
384        }
385    }
386
387    /// Query a set of features that are available on this CPU (LEAF=0x01).
388    ///
389    /// # Platforms
390    /// ✅ AMD ✅ Intel
391    pub fn get_feature_info(&self) -> Option<FeatureInfo> {
392        if self.leaf_is_supported(EAX_FEATURE_INFO) {
393            let res = self.read.cpuid1(EAX_FEATURE_INFO);
394            Some(FeatureInfo {
395                vendor: self.vendor,
396                eax: res.eax,
397                ebx: res.ebx,
398                edx_ecx: FeatureInfoFlags::from_bits_truncate(
399                    ((res.edx as u64) << 32) | (res.ecx as u64),
400                ),
401            })
402        } else {
403            None
404        }
405    }
406
407    /// Query basic information about caches (LEAF=0x02).
408    ///
409    /// # Platforms
410    /// ❌ AMD ✅ Intel
411    pub fn get_cache_info(&self) -> Option<CacheInfoIter> {
412        if self.leaf_is_supported(EAX_CACHE_INFO) {
413            let res = self.read.cpuid1(EAX_CACHE_INFO);
414            Some(CacheInfoIter {
415                current: 1,
416                eax: res.eax,
417                ebx: res.ebx,
418                ecx: res.ecx,
419                edx: res.edx,
420            })
421        } else {
422            None
423        }
424    }
425
426    /// Retrieve serial number of processor (LEAF=0x03).
427    ///
428    /// # Platforms
429    /// ❌ AMD ✅ Intel
430    pub fn get_processor_serial(&self) -> Option<ProcessorSerial> {
431        if self.leaf_is_supported(EAX_PROCESSOR_SERIAL) {
432            // upper 64-96 bits are in res1.eax:
433            let res1 = self.read.cpuid1(EAX_FEATURE_INFO);
434            let res = self.read.cpuid1(EAX_PROCESSOR_SERIAL);
435            Some(ProcessorSerial {
436                ecx: res.ecx,
437                edx: res.edx,
438                eax: res1.eax,
439            })
440        } else {
441            None
442        }
443    }
444
445    /// Retrieve more elaborate information about caches (LEAF=0x04 or 0x8000_001D).
446    ///
447    /// As opposed to [get_cache_info](CpuId::get_cache_info), this will tell us
448    /// about associativity, set size, line size of each level in the cache
449    /// hierarchy.
450    ///
451    /// # Platforms
452    /// 🟡 AMD ✅ Intel
453    pub fn get_cache_parameters(&self) -> Option<CacheParametersIter<R>> {
454        if self.leaf_is_supported(EAX_CACHE_PARAMETERS)
455            || (self.vendor == Vendor::Amd && self.leaf_is_supported(EAX_CACHE_PARAMETERS_AMD))
456        {
457            Some(CacheParametersIter {
458                read: self.read.clone(),
459                leaf: if self.vendor == Vendor::Amd {
460                    EAX_CACHE_PARAMETERS_AMD
461                } else {
462                    EAX_CACHE_PARAMETERS
463                },
464                current: 0,
465            })
466        } else {
467            None
468        }
469    }
470
471    /// Information about how monitor/mwait works on this CPU (LEAF=0x05).
472    ///
473    /// # Platforms
474    /// 🟡 AMD ✅ Intel
475    pub fn get_monitor_mwait_info(&self) -> Option<MonitorMwaitInfo> {
476        if self.leaf_is_supported(EAX_MONITOR_MWAIT_INFO) {
477            let res = self.read.cpuid1(EAX_MONITOR_MWAIT_INFO);
478            Some(MonitorMwaitInfo {
479                eax: res.eax,
480                ebx: res.ebx,
481                ecx: res.ecx,
482                edx: res.edx,
483            })
484        } else {
485            None
486        }
487    }
488
489    /// Query information about thermal and power management features of the CPU (LEAF=0x06).
490    ///
491    /// # Platforms
492    /// 🟡 AMD ✅ Intel
493    pub fn get_thermal_power_info(&self) -> Option<ThermalPowerInfo> {
494        if self.leaf_is_supported(EAX_THERMAL_POWER_INFO) {
495            let res = self.read.cpuid1(EAX_THERMAL_POWER_INFO);
496            Some(ThermalPowerInfo {
497                eax: ThermalPowerFeaturesEax::from_bits_truncate(res.eax),
498                ebx: res.ebx,
499                ecx: ThermalPowerFeaturesEcx::from_bits_truncate(res.ecx),
500                _edx: res.edx,
501            })
502        } else {
503            None
504        }
505    }
506
507    /// Find out about more features supported by this CPU (LEAF=0x07).
508    ///
509    /// # Platforms
510    /// 🟡 AMD ✅ Intel
511    pub fn get_extended_feature_info(&self) -> Option<ExtendedFeatures> {
512        if self.leaf_is_supported(EAX_STRUCTURED_EXTENDED_FEATURE_INFO) {
513            let res = self.read.cpuid1(EAX_STRUCTURED_EXTENDED_FEATURE_INFO);
514            let res1 = self.read.cpuid2(EAX_STRUCTURED_EXTENDED_FEATURE_INFO, 1);
515            Some(ExtendedFeatures {
516                _eax: res.eax,
517                ebx: ExtendedFeaturesEbx::from_bits_truncate(res.ebx),
518                ecx: ExtendedFeaturesEcx::from_bits_truncate(res.ecx),
519                edx: ExtendedFeaturesEdx::from_bits_truncate(res.edx),
520                eax1: ExtendedFeaturesEax1::from_bits_truncate(res1.eax),
521                _ebx1: res1.ebx,
522                _ecx1: res1.ecx,
523                edx1: ExtendedFeaturesEdx1::from_bits_truncate(res1.edx),
524            })
525        } else {
526            None
527        }
528    }
529
530    /// Direct cache access info (LEAF=0x09).
531    ///
532    /// # Platforms
533    /// ❌ AMD ✅ Intel
534    pub fn get_direct_cache_access_info(&self) -> Option<DirectCacheAccessInfo> {
535        if self.leaf_is_supported(EAX_DIRECT_CACHE_ACCESS_INFO) {
536            let res = self.read.cpuid1(EAX_DIRECT_CACHE_ACCESS_INFO);
537            Some(DirectCacheAccessInfo { eax: res.eax })
538        } else {
539            None
540        }
541    }
542
543    /// Info about performance monitoring (LEAF=0x0A).
544    ///
545    /// # Platforms
546    /// ❌ AMD ✅ Intel
547    pub fn get_performance_monitoring_info(&self) -> Option<PerformanceMonitoringInfo> {
548        if self.leaf_is_supported(EAX_PERFORMANCE_MONITOR_INFO) {
549            let res = self.read.cpuid1(EAX_PERFORMANCE_MONITOR_INFO);
550            Some(PerformanceMonitoringInfo {
551                eax: res.eax,
552                ebx: PerformanceMonitoringFeaturesEbx::from_bits_truncate(res.ebx),
553                _ecx: res.ecx,
554                edx: res.edx,
555            })
556        } else {
557            None
558        }
559    }
560
561    /// Information about topology (LEAF=0x0B).
562    ///
563    /// Intel SDM suggests software should check support for leaf 0x1F
564    /// ([`CpuId::get_extended_topology_info_v2`]), and if supported, enumerate
565    /// that leaf instead.
566    ///
567    /// # Platforms
568    /// ✅ AMD ✅ Intel
569    pub fn get_extended_topology_info(&self) -> Option<ExtendedTopologyIter<R>> {
570        if self.leaf_is_supported(EAX_EXTENDED_TOPOLOGY_INFO) {
571            Some(ExtendedTopologyIter {
572                read: self.read.clone(),
573                level: 0,
574                is_v2: false,
575            })
576        } else {
577            None
578        }
579    }
580
581    /// Extended information about topology (LEAF=0x1F).
582    ///
583    /// # Platforms
584    /// ❌ AMD ✅ Intel
585    pub fn get_extended_topology_info_v2(&self) -> Option<ExtendedTopologyIter<R>> {
586        if self.leaf_is_supported(EAX_EXTENDED_TOPOLOGY_INFO_V2) {
587            Some(ExtendedTopologyIter {
588                read: self.read.clone(),
589                level: 0,
590                is_v2: true,
591            })
592        } else {
593            None
594        }
595    }
596
597    /// Information for saving/restoring extended register state (LEAF=0x0D).
598    ///
599    /// # Platforms
600    /// ✅ AMD ✅ Intel
601    pub fn get_extended_state_info(&self) -> Option<ExtendedStateInfo<R>> {
602        if self.leaf_is_supported(EAX_EXTENDED_STATE_INFO) {
603            let res = self.read.cpuid2(EAX_EXTENDED_STATE_INFO, 0);
604            let res1 = self.read.cpuid2(EAX_EXTENDED_STATE_INFO, 1);
605            Some(ExtendedStateInfo {
606                read: self.read.clone(),
607                eax: ExtendedStateInfoXCR0Flags::from_bits_truncate(res.eax),
608                ebx: res.ebx,
609                ecx: res.ecx,
610                _edx: res.edx,
611                eax1: res1.eax,
612                ebx1: res1.ebx,
613                ecx1: ExtendedStateInfoXSSFlags::from_bits_truncate(res1.ecx),
614                _edx1: res1.edx,
615            })
616        } else {
617            None
618        }
619    }
620
621    /// Quality of service monitoring information (LEAF=0x0F).
622    ///
623    /// # Platforms
624    /// ❌ AMD ✅ Intel
625    pub fn get_rdt_monitoring_info(&self) -> Option<RdtMonitoringInfo<R>> {
626        let res = self.read.cpuid1(EAX_RDT_MONITORING);
627
628        if self.leaf_is_supported(EAX_RDT_MONITORING) {
629            Some(RdtMonitoringInfo {
630                read: self.read.clone(),
631                ebx: res.ebx,
632                edx: res.edx,
633            })
634        } else {
635            None
636        }
637    }
638
639    /// Quality of service enforcement information (LEAF=0x10).
640    ///
641    /// # Platforms
642    /// ❌ AMD ✅ Intel
643    pub fn get_rdt_allocation_info(&self) -> Option<RdtAllocationInfo<R>> {
644        let res = self.read.cpuid1(EAX_RDT_ALLOCATION);
645
646        if self.leaf_is_supported(EAX_RDT_ALLOCATION) {
647            Some(RdtAllocationInfo {
648                read: self.read.clone(),
649                ebx: res.ebx,
650            })
651        } else {
652            None
653        }
654    }
655
656    /// Information about secure enclave support (LEAF=0x12).
657    ///
658    /// # Platforms
659    /// ❌ AMD ✅ Intel
660    pub fn get_sgx_info(&self) -> Option<SgxInfo<R>> {
661        // Leaf 12H sub-leaf 0 (ECX = 0) is supported if CPUID.(EAX=07H, ECX=0H):EBX[SGX] = 1.
662        self.get_extended_feature_info().and_then(|info| {
663            if self.leaf_is_supported(EAX_SGX) && info.has_sgx() {
664                let res = self.read.cpuid2(EAX_SGX, 0);
665                let res1 = self.read.cpuid2(EAX_SGX, 1);
666                Some(SgxInfo {
667                    read: self.read.clone(),
668                    eax: res.eax,
669                    ebx: res.ebx,
670                    _ecx: res.ecx,
671                    edx: res.edx,
672                    eax1: res1.eax,
673                    ebx1: res1.ebx,
674                    ecx1: res1.ecx,
675                    edx1: res1.edx,
676                })
677            } else {
678                None
679            }
680        })
681    }
682
683    /// Intel Processor Trace Enumeration Information (LEAF=0x14).
684    ///
685    /// # Platforms
686    /// ❌ AMD ✅ Intel
687    pub fn get_processor_trace_info(&self) -> Option<ProcessorTraceInfo> {
688        if self.leaf_is_supported(EAX_TRACE_INFO) {
689            let res = self.read.cpuid2(EAX_TRACE_INFO, 0);
690            let res1 = if res.eax >= 1 {
691                Some(self.read.cpuid2(EAX_TRACE_INFO, 1))
692            } else {
693                None
694            };
695
696            Some(ProcessorTraceInfo {
697                _eax: res.eax,
698                ebx: res.ebx,
699                ecx: res.ecx,
700                _edx: res.edx,
701                leaf1: res1,
702            })
703        } else {
704            None
705        }
706    }
707
708    /// Time Stamp Counter/Core Crystal Clock Information (LEAF=0x15).
709    ///
710    /// # Platforms
711    /// ❌ AMD ✅ Intel
712    pub fn get_tsc_info(&self) -> Option<TscInfo> {
713        if self.leaf_is_supported(EAX_TIME_STAMP_COUNTER_INFO) {
714            let res = self.read.cpuid2(EAX_TIME_STAMP_COUNTER_INFO, 0);
715            Some(TscInfo {
716                eax: res.eax,
717                ebx: res.ebx,
718                ecx: res.ecx,
719            })
720        } else {
721            None
722        }
723    }
724
725    /// Processor Frequency Information (LEAF=0x16).
726    ///
727    /// # Platforms
728    /// ❌ AMD ✅ Intel
729    pub fn get_processor_frequency_info(&self) -> Option<ProcessorFrequencyInfo> {
730        if self.leaf_is_supported(EAX_FREQUENCY_INFO) {
731            let res = self.read.cpuid1(EAX_FREQUENCY_INFO);
732            Some(ProcessorFrequencyInfo {
733                eax: res.eax,
734                ebx: res.ebx,
735                ecx: res.ecx,
736            })
737        } else {
738            None
739        }
740    }
741
742    /// Contains SoC vendor specific information (LEAF=0x17).
743    ///
744    /// # Platforms
745    /// ❌ AMD ✅ Intel
746    pub fn get_soc_vendor_info(&self) -> Option<SoCVendorInfo<R>> {
747        if self.leaf_is_supported(EAX_SOC_VENDOR_INFO) {
748            let res = self.read.cpuid1(EAX_SOC_VENDOR_INFO);
749            Some(SoCVendorInfo {
750                read: self.read.clone(),
751                eax: res.eax,
752                ebx: res.ebx,
753                ecx: res.ecx,
754                edx: res.edx,
755            })
756        } else {
757            None
758        }
759    }
760
761    /// Query deterministic address translation feature (LEAF=0x18).
762    ///
763    /// # Platforms
764    /// ❌ AMD ✅ Intel
765    pub fn get_deterministic_address_translation_info(&self) -> Option<DatIter<R>> {
766        if self.leaf_is_supported(EAX_DETERMINISTIC_ADDRESS_TRANSLATION_INFO) {
767            let res = self
768                .read
769                .cpuid2(EAX_DETERMINISTIC_ADDRESS_TRANSLATION_INFO, 0);
770            Some(DatIter {
771                read: self.read.clone(),
772                current: 0,
773                count: res.eax,
774            })
775        } else {
776            None
777        }
778    }
779
780    /// Returns information provided by the hypervisor, if running
781    /// in a virtual environment (LEAF=0x4000_00xx).
782    ///
783    /// # Platform
784    /// Needs to be a virtual CPU to be supported.
785    pub fn get_hypervisor_info(&self) -> Option<HypervisorInfo<R>> {
786        // We only fetch HypervisorInfo, if the Hypervisor-Flag is set.
787        // See https://github.com/gz/rust-cpuid/issues/52
788        self.get_feature_info()
789            .filter(|fi| fi.has_hypervisor())
790            .and_then(|_| {
791                let res = self.read.cpuid1(EAX_HYPERVISOR_INFO);
792                if res.eax > 0 {
793                    Some(HypervisorInfo {
794                        read: self.read.clone(),
795                        res,
796                    })
797                } else {
798                    None
799                }
800            })
801    }
802
803    /// Extended Processor and Processor Feature Identifiers (LEAF=0x8000_0001).
804    ///
805    /// # Platforms
806    /// ✅ AMD 🟡 Intel
807    pub fn get_extended_processor_and_feature_identifiers(
808        &self,
809    ) -> Option<ExtendedProcessorFeatureIdentifiers> {
810        if self.leaf_is_supported(EAX_EXTENDED_PROCESSOR_AND_FEATURE_IDENTIFIERS) {
811            Some(ExtendedProcessorFeatureIdentifiers::new(
812                self.vendor,
813                self.read
814                    .cpuid1(EAX_EXTENDED_PROCESSOR_AND_FEATURE_IDENTIFIERS),
815            ))
816        } else {
817            None
818        }
819    }
820
821    /// Retrieve processor brand string (LEAF=0x8000_000{2..4}).
822    ///
823    /// # Platforms
824    /// ✅ AMD ✅ Intel
825    pub fn get_processor_brand_string(&self) -> Option<ProcessorBrandString> {
826        if self.leaf_is_supported(EAX_EXTENDED_BRAND_STRING)
827            && self.leaf_is_supported(EAX_EXTENDED_BRAND_STRING + 1)
828            && self.leaf_is_supported(EAX_EXTENDED_BRAND_STRING + 2)
829        {
830            Some(ProcessorBrandString::new([
831                self.read.cpuid1(EAX_EXTENDED_BRAND_STRING),
832                self.read.cpuid1(EAX_EXTENDED_BRAND_STRING + 1),
833                self.read.cpuid1(EAX_EXTENDED_BRAND_STRING + 2),
834            ]))
835        } else {
836            None
837        }
838    }
839
840    /// L1 Instruction Cache Information (LEAF=0x8000_0005)
841    ///
842    /// # Platforms
843    /// ✅ AMD ❌ Intel (reserved)
844    pub fn get_l1_cache_and_tlb_info(&self) -> Option<L1CacheTlbInfo> {
845        if self.vendor == Vendor::Amd && self.leaf_is_supported(EAX_L1_CACHE_INFO) {
846            Some(L1CacheTlbInfo::new(self.read.cpuid1(EAX_L1_CACHE_INFO)))
847        } else {
848            None
849        }
850    }
851
852    /// L2/L3 Cache and TLB Information (LEAF=0x8000_0006).
853    ///
854    /// # Platforms
855    /// ✅ AMD 🟡 Intel
856    pub fn get_l2_l3_cache_and_tlb_info(&self) -> Option<L2And3CacheTlbInfo> {
857        if self.leaf_is_supported(EAX_L2_L3_CACHE_INFO) {
858            Some(L2And3CacheTlbInfo::new(
859                self.read.cpuid1(EAX_L2_L3_CACHE_INFO),
860            ))
861        } else {
862            None
863        }
864    }
865
866    /// Advanced Power Management Information (LEAF=0x8000_0007).
867    ///
868    /// # Platforms
869    /// ✅ AMD 🟡 Intel
870    pub fn get_advanced_power_mgmt_info(&self) -> Option<ApmInfo> {
871        if self.leaf_is_supported(EAX_ADVANCED_POWER_MGMT_INFO) {
872            Some(ApmInfo::new(self.read.cpuid1(EAX_ADVANCED_POWER_MGMT_INFO)))
873        } else {
874            None
875        }
876    }
877
878    /// Processor Capacity Parameters and Extended Feature Identification (LEAF=0x8000_0008).
879    ///
880    /// # Platforms
881    /// ✅ AMD 🟡 Intel
882    pub fn get_processor_capacity_feature_info(&self) -> Option<ProcessorCapacityAndFeatureInfo> {
883        if self.leaf_is_supported(EAX_PROCESSOR_CAPACITY_INFO) {
884            Some(ProcessorCapacityAndFeatureInfo::new(
885                self.read.cpuid1(EAX_PROCESSOR_CAPACITY_INFO),
886            ))
887        } else {
888            None
889        }
890    }
891
892    /// This function provides information about the SVM features that the processory
893    /// supports. (LEAF=0x8000_000A)
894    ///
895    /// If SVM is not supported if [ExtendedProcessorFeatureIdentifiers::has_svm] is
896    /// false, this function is reserved then.
897    ///
898    /// # Platforms
899    /// ✅ AMD ❌ Intel
900    pub fn get_svm_info(&self) -> Option<SvmFeatures> {
901        let has_svm = self
902            .get_extended_processor_and_feature_identifiers()
903            .map_or(false, |f| f.has_svm());
904        if has_svm && self.leaf_is_supported(EAX_SVM_FEATURES) {
905            Some(SvmFeatures::new(self.read.cpuid1(EAX_SVM_FEATURES)))
906        } else {
907            None
908        }
909    }
910
911    /// TLB 1-GiB Pages Information (LEAF=0x8000_0019)
912    ///
913    /// # Platforms
914    /// ✅ AMD ❌ Intel
915    pub fn get_tlb_1gb_page_info(&self) -> Option<Tlb1gbPageInfo> {
916        if self.leaf_is_supported(EAX_TLB_1GB_PAGE_INFO) {
917            Some(Tlb1gbPageInfo::new(self.read.cpuid1(EAX_TLB_1GB_PAGE_INFO)))
918        } else {
919            None
920        }
921    }
922
923    /// Informations about performance optimization (LEAF=0x8000_001A)
924    ///
925    /// # Platforms
926    /// ✅ AMD ❌ Intel (reserved)
927    pub fn get_performance_optimization_info(&self) -> Option<PerformanceOptimizationInfo> {
928        if self.leaf_is_supported(EAX_PERFORMANCE_OPTIMIZATION_INFO) {
929            Some(PerformanceOptimizationInfo::new(
930                self.read.cpuid1(EAX_PERFORMANCE_OPTIMIZATION_INFO),
931            ))
932        } else {
933            None
934        }
935    }
936
937    /// Informations about processor topology (LEAF=0x8000_001E)
938    ///
939    /// # Platforms
940    /// ✅ AMD ❌ Intel (reserved)
941    pub fn get_processor_topology_info(&self) -> Option<ProcessorTopologyInfo> {
942        if self.leaf_is_supported(EAX_PROCESSOR_TOPOLOGY_INFO) {
943            Some(ProcessorTopologyInfo::new(
944                self.read.cpuid1(EAX_PROCESSOR_TOPOLOGY_INFO),
945            ))
946        } else {
947            None
948        }
949    }
950
951    /// Informations about memory encryption support (LEAF=0x8000_001F)
952    ///
953    /// # Platforms
954    /// ✅ AMD ❌ Intel (reserved)
955    pub fn get_memory_encryption_info(&self) -> Option<MemoryEncryptionInfo> {
956        if self.leaf_is_supported(EAX_MEMORY_ENCRYPTION_INFO) {
957            Some(MemoryEncryptionInfo::new(
958                self.read.cpuid1(EAX_MEMORY_ENCRYPTION_INFO),
959            ))
960        } else {
961            None
962        }
963    }
964}
965
966impl<R: CpuIdReader> Debug for CpuId<R> {
967    fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
968        f.debug_struct("CpuId")
969            .field("vendor", &self.vendor)
970            // .field("supported_leafs", &(self.supported_leafs as *const u32))
971            // .field("supported_extended_leafs", &(self.supported_extended_leafs as *const u32))
972            .field("vendor_info", &self.get_vendor_info())
973            .field("feature_info", &self.get_feature_info())
974            .field("cache_info", &self.get_cache_info())
975            .field("processor_serial", &self.get_processor_serial())
976            .field("cache_parameters", &self.get_cache_parameters())
977            .field("monitor_mwait_info", &self.get_monitor_mwait_info())
978            .field("thermal_power_info", &self.get_thermal_power_info())
979            .field("extended_feature_info", &self.get_extended_feature_info())
980            .field(
981                "direct_cache_access_info",
982                &self.get_direct_cache_access_info(),
983            )
984            .field(
985                "performance_monitoring_info",
986                &self.get_performance_monitoring_info(),
987            )
988            .field("extended_topology_info", &self.get_extended_topology_info())
989            .field("extended_state_info", &self.get_extended_state_info())
990            .field("rdt_monitoring_info", &self.get_rdt_monitoring_info())
991            .field("rdt_allocation_info", &self.get_rdt_allocation_info())
992            .field("sgx_info", &self.get_sgx_info())
993            .field("processor_trace_info", &self.get_processor_trace_info())
994            .field("tsc_info", &self.get_tsc_info())
995            .field(
996                "processor_frequency_info",
997                &self.get_processor_frequency_info(),
998            )
999            .field(
1000                "deterministic_address_translation_info",
1001                &self.get_deterministic_address_translation_info(),
1002            )
1003            .field("soc_vendor_info", &self.get_soc_vendor_info())
1004            .field("hypervisor_info", &self.get_hypervisor_info())
1005            .field(
1006                "extended_processor_and_feature_identifiers",
1007                &self.get_extended_processor_and_feature_identifiers(),
1008            )
1009            .field("processor_brand_string", &self.get_processor_brand_string())
1010            .field("l1_cache_and_tlb_info", &self.get_l1_cache_and_tlb_info())
1011            .field(
1012                "l2_l3_cache_and_tlb_info",
1013                &self.get_l2_l3_cache_and_tlb_info(),
1014            )
1015            .field(
1016                "advanced_power_mgmt_info",
1017                &self.get_advanced_power_mgmt_info(),
1018            )
1019            .field(
1020                "processor_capacity_feature_info",
1021                &self.get_processor_capacity_feature_info(),
1022            )
1023            .field("svm_info", &self.get_svm_info())
1024            .field("tlb_1gb_page_info", &self.get_tlb_1gb_page_info())
1025            .field(
1026                "performance_optimization_info",
1027                &self.get_performance_optimization_info(),
1028            )
1029            .field(
1030                "processor_topology_info",
1031                &self.get_processor_topology_info(),
1032            )
1033            .field("memory_encryption_info", &self.get_memory_encryption_info())
1034            .finish()
1035    }
1036}
1037
1038/// Vendor Info String (LEAF=0x0)
1039///
1040/// A string that can be for example "AuthenticAMD" or "GenuineIntel".
1041///
1042/// # Technical Background
1043///
1044/// The vendor info is a 12-byte (96 bit) long string stored in `ebx`, `edx` and
1045/// `ecx` by the corresponding `cpuid` instruction.
1046///
1047/// # Platforms
1048/// ✅ AMD ✅ Intel
1049#[derive(PartialEq, Eq)]
1050#[repr(C)]
1051pub struct VendorInfo {
1052    ebx: u32,
1053    edx: u32,
1054    ecx: u32,
1055}
1056
1057impl VendorInfo {
1058    /// Return vendor identification as human readable string.
1059    pub fn as_str(&self) -> &str {
1060        let brand_string_start = self as *const VendorInfo as *const u8;
1061        let slice = unsafe {
1062            // Safety: VendorInfo is laid out with repr(C) and exactly
1063            // 12 byte long without any padding.
1064            slice::from_raw_parts(brand_string_start, size_of::<VendorInfo>())
1065        };
1066
1067        str::from_utf8(slice).unwrap_or("InvalidVendorString")
1068    }
1069
1070    #[deprecated(
1071        since = "10.0.0",
1072        note = "Use idiomatic function name `as_str` instead"
1073    )]
1074    pub fn as_string(&self) -> &str {
1075        self.as_str()
1076    }
1077}
1078
1079impl Debug for VendorInfo {
1080    fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
1081        f.debug_struct("VendorInfo")
1082            .field("brand_string", &self.as_str())
1083            .finish()
1084    }
1085}
1086
1087impl fmt::Display for VendorInfo {
1088    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1089        write!(f, "{}", self.as_str())
1090    }
1091}
1092
1093/// Iterates over cache information (LEAF=0x02).
1094///
1095/// This will just return an index into a static table of cache descriptions
1096/// (see [CACHE_INFO_TABLE](crate::CACHE_INFO_TABLE)).
1097///
1098/// # Platforms
1099/// ❌ AMD ✅ Intel
1100#[derive(PartialEq, Eq, Clone)]
1101pub struct CacheInfoIter {
1102    current: u32,
1103    eax: u32,
1104    ebx: u32,
1105    ecx: u32,
1106    edx: u32,
1107}
1108
1109impl Iterator for CacheInfoIter {
1110    type Item = CacheInfo;
1111
1112    /// Iterate over all cache information.
1113    fn next(&mut self) -> Option<CacheInfo> {
1114        // Every byte of the 4 register values returned by cpuid
1115        // can contain information about a cache (except the
1116        // very first one).
1117        if self.current >= 4 * 4 {
1118            return None;
1119        }
1120        let reg_index = self.current % 4;
1121        let byte_index = self.current / 4;
1122
1123        let reg = match reg_index {
1124            0 => self.eax,
1125            1 => self.ebx,
1126            2 => self.ecx,
1127            3 => self.edx,
1128            _ => unreachable!(),
1129        };
1130
1131        let byte = match byte_index {
1132            0 => reg,
1133            1 => reg >> 8,
1134            2 => reg >> 16,
1135            3 => reg >> 24,
1136            _ => unreachable!(),
1137        } as u8;
1138
1139        if byte == 0 {
1140            self.current += 1;
1141            return self.next();
1142        }
1143
1144        for cache_info in CACHE_INFO_TABLE.iter() {
1145            if cache_info.num == byte {
1146                self.current += 1;
1147                return Some(*cache_info);
1148            }
1149        }
1150
1151        None
1152    }
1153}
1154
1155impl Debug for CacheInfoIter {
1156    fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
1157        let mut debug = f.debug_list();
1158        self.clone().for_each(|ref item| {
1159            debug.entry(item);
1160        });
1161        debug.finish()
1162    }
1163}
1164
1165/// What type of cache are we dealing with?
1166#[derive(Copy, Clone, Debug)]
1167pub enum CacheInfoType {
1168    General,
1169    Cache,
1170    TLB,
1171    STLB,
1172    DTLB,
1173    Prefetch,
1174}
1175
1176/// Describes any kind of cache (TLB, Data and Instruction caches plus prefetchers).
1177#[derive(Copy, Clone)]
1178pub struct CacheInfo {
1179    /// Number as retrieved from cpuid
1180    pub num: u8,
1181    /// Cache type
1182    pub typ: CacheInfoType,
1183}
1184
1185impl CacheInfo {
1186    /// Description of the cache (from Intel Manual)
1187    pub fn desc(&self) -> &'static str {
1188        match self.num {
1189            0x00 => "Null descriptor, this byte contains no information",
1190            0x01 => "Instruction TLB: 4 KByte pages, 4-way set associative, 32 entries",
1191            0x02 => "Instruction TLB: 4 MByte pages, fully associative, 2 entries",
1192            0x03 => "Data TLB: 4 KByte pages, 4-way set associative, 64 entries",
1193            0x04 => "Data TLB: 4 MByte pages, 4-way set associative, 8 entries",
1194            0x05 => "Data TLB1: 4 MByte pages, 4-way set associative, 32 entries",
1195            0x06 => "1st-level instruction cache: 8 KBytes, 4-way set associative, 32 byte line size",
1196            0x08 => "1st-level instruction cache: 16 KBytes, 4-way set associative, 32 byte line size",
1197            0x09 => "1st-level instruction cache: 32KBytes, 4-way set associative, 64 byte line size",
1198            0x0A => "1st-level data cache: 8 KBytes, 2-way set associative, 32 byte line size",
1199            0x0B => "Instruction TLB: 4 MByte pages, 4-way set associative, 4 entries",
1200            0x0C => "1st-level data cache: 16 KBytes, 4-way set associative, 32 byte line size",
1201            0x0D => "1st-level data cache: 16 KBytes, 4-way set associative, 64 byte line size",
1202            0x0E => "1st-level data cache: 24 KBytes, 6-way set associative, 64 byte line size",
1203            0x1D => "2nd-level cache: 128 KBytes, 2-way set associative, 64 byte line size",
1204            0x21 => "2nd-level cache: 256 KBytes, 8-way set associative, 64 byte line size",
1205            0x22 => "3rd-level cache: 512 KBytes, 4-way set associative, 64 byte line size, 2 lines per sector",
1206            0x23 => "3rd-level cache: 1 MBytes, 8-way set associative, 64 byte line size, 2 lines per sector",
1207            0x24 => "2nd-level cache: 1 MBytes, 16-way set associative, 64 byte line size",
1208            0x25 => "3rd-level cache: 2 MBytes, 8-way set associative, 64 byte line size, 2 lines per sector",
1209            0x29 => "3rd-level cache: 4 MBytes, 8-way set associative, 64 byte line size, 2 lines per sector",
1210            0x2C => "1st-level data cache: 32 KBytes, 8-way set associative, 64 byte line size",
1211            0x30 => "1st-level instruction cache: 32 KBytes, 8-way set associative, 64 byte line size",
1212            0x40 => "No 2nd-level cache or, if processor contains a valid 2nd-level cache, no 3rd-level cache",
1213            0x41 => "2nd-level cache: 128 KBytes, 4-way set associative, 32 byte line size",
1214            0x42 => "2nd-level cache: 256 KBytes, 4-way set associative, 32 byte line size",
1215            0x43 => "2nd-level cache: 512 KBytes, 4-way set associative, 32 byte line size",
1216            0x44 => "2nd-level cache: 1 MByte, 4-way set associative, 32 byte line size",
1217            0x45 => "2nd-level cache: 2 MByte, 4-way set associative, 32 byte line size",
1218            0x46 => "3rd-level cache: 4 MByte, 4-way set associative, 64 byte line size",
1219            0x47 => "3rd-level cache: 8 MByte, 8-way set associative, 64 byte line size",
1220            0x48 => "2nd-level cache: 3MByte, 12-way set associative, 64 byte line size",
1221            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",
1222            0x4A => "3rd-level cache: 6MByte, 12-way set associative, 64 byte line size",
1223            0x4B => "3rd-level cache: 8MByte, 16-way set associative, 64 byte line size",
1224            0x4C => "3rd-level cache: 12MByte, 12-way set associative, 64 byte line size",
1225            0x4D => "3rd-level cache: 16MByte, 16-way set associative, 64 byte line size",
1226            0x4E => "2nd-level cache: 6MByte, 24-way set associative, 64 byte line size",
1227            0x4F => "Instruction TLB: 4 KByte pages, 32 entries",
1228            0x50 => "Instruction TLB: 4 KByte and 2-MByte or 4-MByte pages, 64 entries",
1229            0x51 => "Instruction TLB: 4 KByte and 2-MByte or 4-MByte pages, 128 entries",
1230            0x52 => "Instruction TLB: 4 KByte and 2-MByte or 4-MByte pages, 256 entries",
1231            0x55 => "Instruction TLB: 2-MByte or 4-MByte pages, fully associative, 7 entries",
1232            0x56 => "Data TLB0: 4 MByte pages, 4-way set associative, 16 entries",
1233            0x57 => "Data TLB0: 4 KByte pages, 4-way associative, 16 entries",
1234            0x59 => "Data TLB0: 4 KByte pages, fully associative, 16 entries",
1235            0x5A => "Data TLB0: 2-MByte or 4 MByte pages, 4-way set associative, 32 entries",
1236            0x5B => "Data TLB: 4 KByte and 4 MByte pages, 64 entries",
1237            0x5C => "Data TLB: 4 KByte and 4 MByte pages,128 entries",
1238            0x5D => "Data TLB: 4 KByte and 4 MByte pages,256 entries",
1239            0x60 => "1st-level data cache: 16 KByte, 8-way set associative, 64 byte line size",
1240            0x61 => "Instruction TLB: 4 KByte pages, fully associative, 48 entries",
1241            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",
1242            0x64 => "Data TLB: 4 KByte pages, 4-way set associative, 512 entries",
1243            0x66 => "1st-level data cache: 8 KByte, 4-way set associative, 64 byte line size",
1244            0x67 => "1st-level data cache: 16 KByte, 4-way set associative, 64 byte line size",
1245            0x68 => "1st-level data cache: 32 KByte, 4-way set associative, 64 byte line size",
1246            0x6A => "uTLB: 4 KByte pages, 8-way set associative, 64 entries",
1247            0x6B => "DTLB: 4 KByte pages, 8-way set associative, 256 entries",
1248            0x6C => "DTLB: 2M/4M pages, 8-way set associative, 128 entries",
1249            0x6D => "DTLB: 1 GByte pages, fully associative, 16 entries",
1250            0x70 => "Trace cache: 12 K-μop, 8-way set associative",
1251            0x71 => "Trace cache: 16 K-μop, 8-way set associative",
1252            0x72 => "Trace cache: 32 K-μop, 8-way set associative",
1253            0x76 => "Instruction TLB: 2M/4M pages, fully associative, 8 entries",
1254            0x78 => "2nd-level cache: 1 MByte, 4-way set associative, 64byte line size",
1255            0x79 => "2nd-level cache: 128 KByte, 8-way set associative, 64 byte line size, 2 lines per sector",
1256            0x7A => "2nd-level cache: 256 KByte, 8-way set associative, 64 byte line size, 2 lines per sector",
1257            0x7B => "2nd-level cache: 512 KByte, 8-way set associative, 64 byte line size, 2 lines per sector",
1258            0x7C => "2nd-level cache: 1 MByte, 8-way set associative, 64 byte line size, 2 lines per sector",
1259            0x7D => "2nd-level cache: 2 MByte, 8-way set associative, 64byte line size",
1260            0x7F => "2nd-level cache: 512 KByte, 2-way set associative, 64-byte line size",
1261            0x80 => "2nd-level cache: 512 KByte, 8-way set associative, 64-byte line size",
1262            0x82 => "2nd-level cache: 256 KByte, 8-way set associative, 32 byte line size",
1263            0x83 => "2nd-level cache: 512 KByte, 8-way set associative, 32 byte line size",
1264            0x84 => "2nd-level cache: 1 MByte, 8-way set associative, 32 byte line size",
1265            0x85 => "2nd-level cache: 2 MByte, 8-way set associative, 32 byte line size",
1266            0x86 => "2nd-level cache: 512 KByte, 4-way set associative, 64 byte line size",
1267            0x87 => "2nd-level cache: 1 MByte, 8-way set associative, 64 byte line size",
1268            0xA0 => "DTLB: 4k pages, fully associative, 32 entries",
1269            0xB0 => "Instruction TLB: 4 KByte pages, 4-way set associative, 128 entries",
1270            0xB1 => "Instruction TLB: 2M pages, 4-way, 8 entries or 4M pages, 4-way, 4 entries",
1271            0xB2 => "Instruction TLB: 4KByte pages, 4-way set associative, 64 entries",
1272            0xB3 => "Data TLB: 4 KByte pages, 4-way set associative, 128 entries",
1273            0xB4 => "Data TLB1: 4 KByte pages, 4-way associative, 256 entries",
1274            0xB5 => "Instruction TLB: 4KByte pages, 8-way set associative, 64 entries",
1275            0xB6 => "Instruction TLB: 4KByte pages, 8-way set associative, 128 entries",
1276            0xBA => "Data TLB1: 4 KByte pages, 4-way associative, 64 entries",
1277            0xC0 => "Data TLB: 4 KByte and 4 MByte pages, 4-way associative, 8 entries",
1278            0xC1 => "Shared 2nd-Level TLB: 4 KByte/2MByte pages, 8-way associative, 1024 entries",
1279            0xC2 => "DTLB: 2 MByte/$MByte pages, 4-way associative, 16 entries",
1280            0xC3 => "Shared 2nd-Level TLB: 4 KByte /2 MByte pages, 6-way associative, 1536 entries. Also 1GBbyte pages, 4-way, 16 entries.",
1281            0xC4 => "DTLB: 2M/4M Byte pages, 4-way associative, 32 entries",
1282            0xCA => "Shared 2nd-Level TLB: 4 KByte pages, 4-way associative, 512 entries",
1283            0xD0 => "3rd-level cache: 512 KByte, 4-way set associative, 64 byte line size",
1284            0xD1 => "3rd-level cache: 1 MByte, 4-way set associative, 64 byte line size",
1285            0xD2 => "3rd-level cache: 2 MByte, 4-way set associative, 64 byte line size",
1286            0xD6 => "3rd-level cache: 1 MByte, 8-way set associative, 64 byte line size",
1287            0xD7 => "3rd-level cache: 2 MByte, 8-way set associative, 64 byte line size",
1288            0xD8 => "3rd-level cache: 4 MByte, 8-way set associative, 64 byte line size",
1289            0xDC => "3rd-level cache: 1.5 MByte, 12-way set associative, 64 byte line size",
1290            0xDD => "3rd-level cache: 3 MByte, 12-way set associative, 64 byte line size",
1291            0xDE => "3rd-level cache: 6 MByte, 12-way set associative, 64 byte line size",
1292            0xE2 => "3rd-level cache: 2 MByte, 16-way set associative, 64 byte line size",
1293            0xE3 => "3rd-level cache: 4 MByte, 16-way set associative, 64 byte line size",
1294            0xE4 => "3rd-level cache: 8 MByte, 16-way set associative, 64 byte line size",
1295            0xEA => "3rd-level cache: 12MByte, 24-way set associative, 64 byte line size",
1296            0xEB => "3rd-level cache: 18MByte, 24-way set associative, 64 byte line size",
1297            0xEC => "3rd-level cache: 24MByte, 24-way set associative, 64 byte line size",
1298            0xF0 => "64-Byte prefetching",
1299            0xF1 => "128-Byte prefetching",
1300            0xFE => "CPUID leaf 2 does not report TLB descriptor information; use CPUID leaf 18H to query TLB and other address translation parameters.",
1301            0xFF => "CPUID leaf 2 does not report cache descriptor information, use CPUID leaf 4 to query cache parameters",
1302            _ => "Unknown cache type!"
1303        }
1304    }
1305}
1306
1307impl Debug for CacheInfo {
1308    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
1309        f.debug_struct("CacheInfo")
1310            .field("typ", &self.typ)
1311            .field("desc", &self.desc())
1312            .finish()
1313    }
1314}
1315
1316impl fmt::Display for CacheInfo {
1317    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1318        let typ = match self.typ {
1319            CacheInfoType::General => "N/A",
1320            CacheInfoType::Cache => "Cache",
1321            CacheInfoType::TLB => "TLB",
1322            CacheInfoType::STLB => "STLB",
1323            CacheInfoType::DTLB => "DTLB",
1324            CacheInfoType::Prefetch => "Prefetcher",
1325        };
1326
1327        write!(f, "{:x}:\t {}: {}", self.num, typ, self.desc())
1328    }
1329}
1330
1331/// This table is taken from Intel manual (Section CPUID instruction).
1332pub const CACHE_INFO_TABLE: [CacheInfo; 108] = [
1333    CacheInfo {
1334        num: 0x00,
1335        typ: CacheInfoType::General,
1336    },
1337    CacheInfo {
1338        num: 0x01,
1339        typ: CacheInfoType::TLB,
1340    },
1341    CacheInfo {
1342        num: 0x02,
1343        typ: CacheInfoType::TLB,
1344    },
1345    CacheInfo {
1346        num: 0x03,
1347        typ: CacheInfoType::TLB,
1348    },
1349    CacheInfo {
1350        num: 0x04,
1351        typ: CacheInfoType::TLB,
1352    },
1353    CacheInfo {
1354        num: 0x05,
1355        typ: CacheInfoType::TLB,
1356    },
1357    CacheInfo {
1358        num: 0x06,
1359        typ: CacheInfoType::Cache,
1360    },
1361    CacheInfo {
1362        num: 0x08,
1363        typ: CacheInfoType::Cache,
1364    },
1365    CacheInfo {
1366        num: 0x09,
1367        typ: CacheInfoType::Cache,
1368    },
1369    CacheInfo {
1370        num: 0x0A,
1371        typ: CacheInfoType::Cache,
1372    },
1373    CacheInfo {
1374        num: 0x0B,
1375        typ: CacheInfoType::TLB,
1376    },
1377    CacheInfo {
1378        num: 0x0C,
1379        typ: CacheInfoType::Cache,
1380    },
1381    CacheInfo {
1382        num: 0x0D,
1383        typ: CacheInfoType::Cache,
1384    },
1385    CacheInfo {
1386        num: 0x0E,
1387        typ: CacheInfoType::Cache,
1388    },
1389    CacheInfo {
1390        num: 0x21,
1391        typ: CacheInfoType::Cache,
1392    },
1393    CacheInfo {
1394        num: 0x22,
1395        typ: CacheInfoType::Cache,
1396    },
1397    CacheInfo {
1398        num: 0x23,
1399        typ: CacheInfoType::Cache,
1400    },
1401    CacheInfo {
1402        num: 0x24,
1403        typ: CacheInfoType::Cache,
1404    },
1405    CacheInfo {
1406        num: 0x25,
1407        typ: CacheInfoType::Cache,
1408    },
1409    CacheInfo {
1410        num: 0x29,
1411        typ: CacheInfoType::Cache,
1412    },
1413    CacheInfo {
1414        num: 0x2C,
1415        typ: CacheInfoType::Cache,
1416    },
1417    CacheInfo {
1418        num: 0x30,
1419        typ: CacheInfoType::Cache,
1420    },
1421    CacheInfo {
1422        num: 0x40,
1423        typ: CacheInfoType::Cache,
1424    },
1425    CacheInfo {
1426        num: 0x41,
1427        typ: CacheInfoType::Cache,
1428    },
1429    CacheInfo {
1430        num: 0x42,
1431        typ: CacheInfoType::Cache,
1432    },
1433    CacheInfo {
1434        num: 0x43,
1435        typ: CacheInfoType::Cache,
1436    },
1437    CacheInfo {
1438        num: 0x44,
1439        typ: CacheInfoType::Cache,
1440    },
1441    CacheInfo {
1442        num: 0x45,
1443        typ: CacheInfoType::Cache,
1444    },
1445    CacheInfo {
1446        num: 0x46,
1447        typ: CacheInfoType::Cache,
1448    },
1449    CacheInfo {
1450        num: 0x47,
1451        typ: CacheInfoType::Cache,
1452    },
1453    CacheInfo {
1454        num: 0x48,
1455        typ: CacheInfoType::Cache,
1456    },
1457    CacheInfo {
1458        num: 0x49,
1459        typ: CacheInfoType::Cache,
1460    },
1461    CacheInfo {
1462        num: 0x4A,
1463        typ: CacheInfoType::Cache,
1464    },
1465    CacheInfo {
1466        num: 0x4B,
1467        typ: CacheInfoType::Cache,
1468    },
1469    CacheInfo {
1470        num: 0x4C,
1471        typ: CacheInfoType::Cache,
1472    },
1473    CacheInfo {
1474        num: 0x4D,
1475        typ: CacheInfoType::Cache,
1476    },
1477    CacheInfo {
1478        num: 0x4E,
1479        typ: CacheInfoType::Cache,
1480    },
1481    CacheInfo {
1482        num: 0x4F,
1483        typ: CacheInfoType::TLB,
1484    },
1485    CacheInfo {
1486        num: 0x50,
1487        typ: CacheInfoType::TLB,
1488    },
1489    CacheInfo {
1490        num: 0x51,
1491        typ: CacheInfoType::TLB,
1492    },
1493    CacheInfo {
1494        num: 0x52,
1495        typ: CacheInfoType::TLB,
1496    },
1497    CacheInfo {
1498        num: 0x55,
1499        typ: CacheInfoType::TLB,
1500    },
1501    CacheInfo {
1502        num: 0x56,
1503        typ: CacheInfoType::TLB,
1504    },
1505    CacheInfo {
1506        num: 0x57,
1507        typ: CacheInfoType::TLB,
1508    },
1509    CacheInfo {
1510        num: 0x59,
1511        typ: CacheInfoType::TLB,
1512    },
1513    CacheInfo {
1514        num: 0x5A,
1515        typ: CacheInfoType::TLB,
1516    },
1517    CacheInfo {
1518        num: 0x5B,
1519        typ: CacheInfoType::TLB,
1520    },
1521    CacheInfo {
1522        num: 0x5C,
1523        typ: CacheInfoType::TLB,
1524    },
1525    CacheInfo {
1526        num: 0x5D,
1527        typ: CacheInfoType::TLB,
1528    },
1529    CacheInfo {
1530        num: 0x60,
1531        typ: CacheInfoType::Cache,
1532    },
1533    CacheInfo {
1534        num: 0x61,
1535        typ: CacheInfoType::TLB,
1536    },
1537    CacheInfo {
1538        num: 0x63,
1539        typ: CacheInfoType::TLB,
1540    },
1541    CacheInfo {
1542        num: 0x66,
1543        typ: CacheInfoType::Cache,
1544    },
1545    CacheInfo {
1546        num: 0x67,
1547        typ: CacheInfoType::Cache,
1548    },
1549    CacheInfo {
1550        num: 0x68,
1551        typ: CacheInfoType::Cache,
1552    },
1553    CacheInfo {
1554        num: 0x6A,
1555        typ: CacheInfoType::Cache,
1556    },
1557    CacheInfo {
1558        num: 0x6B,
1559        typ: CacheInfoType::Cache,
1560    },
1561    CacheInfo {
1562        num: 0x6C,
1563        typ: CacheInfoType::Cache,
1564    },
1565    CacheInfo {
1566        num: 0x6D,
1567        typ: CacheInfoType::Cache,
1568    },
1569    CacheInfo {
1570        num: 0x70,
1571        typ: CacheInfoType::Cache,
1572    },
1573    CacheInfo {
1574        num: 0x71,
1575        typ: CacheInfoType::Cache,
1576    },
1577    CacheInfo {
1578        num: 0x72,
1579        typ: CacheInfoType::Cache,
1580    },
1581    CacheInfo {
1582        num: 0x76,
1583        typ: CacheInfoType::TLB,
1584    },
1585    CacheInfo {
1586        num: 0x78,
1587        typ: CacheInfoType::Cache,
1588    },
1589    CacheInfo {
1590        num: 0x79,
1591        typ: CacheInfoType::Cache,
1592    },
1593    CacheInfo {
1594        num: 0x7A,
1595        typ: CacheInfoType::Cache,
1596    },
1597    CacheInfo {
1598        num: 0x7B,
1599        typ: CacheInfoType::Cache,
1600    },
1601    CacheInfo {
1602        num: 0x7C,
1603        typ: CacheInfoType::Cache,
1604    },
1605    CacheInfo {
1606        num: 0x7D,
1607        typ: CacheInfoType::Cache,
1608    },
1609    CacheInfo {
1610        num: 0x7F,
1611        typ: CacheInfoType::Cache,
1612    },
1613    CacheInfo {
1614        num: 0x80,
1615        typ: CacheInfoType::Cache,
1616    },
1617    CacheInfo {
1618        num: 0x82,
1619        typ: CacheInfoType::Cache,
1620    },
1621    CacheInfo {
1622        num: 0x83,
1623        typ: CacheInfoType::Cache,
1624    },
1625    CacheInfo {
1626        num: 0x84,
1627        typ: CacheInfoType::Cache,
1628    },
1629    CacheInfo {
1630        num: 0x85,
1631        typ: CacheInfoType::Cache,
1632    },
1633    CacheInfo {
1634        num: 0x86,
1635        typ: CacheInfoType::Cache,
1636    },
1637    CacheInfo {
1638        num: 0x87,
1639        typ: CacheInfoType::Cache,
1640    },
1641    CacheInfo {
1642        num: 0xB0,
1643        typ: CacheInfoType::TLB,
1644    },
1645    CacheInfo {
1646        num: 0xB1,
1647        typ: CacheInfoType::TLB,
1648    },
1649    CacheInfo {
1650        num: 0xB2,
1651        typ: CacheInfoType::TLB,
1652    },
1653    CacheInfo {
1654        num: 0xB3,
1655        typ: CacheInfoType::TLB,
1656    },
1657    CacheInfo {
1658        num: 0xB4,
1659        typ: CacheInfoType::TLB,
1660    },
1661    CacheInfo {
1662        num: 0xB5,
1663        typ: CacheInfoType::TLB,
1664    },
1665    CacheInfo {
1666        num: 0xB6,
1667        typ: CacheInfoType::TLB,
1668    },
1669    CacheInfo {
1670        num: 0xBA,
1671        typ: CacheInfoType::TLB,
1672    },
1673    CacheInfo {
1674        num: 0xC0,
1675        typ: CacheInfoType::TLB,
1676    },
1677    CacheInfo {
1678        num: 0xC1,
1679        typ: CacheInfoType::STLB,
1680    },
1681    CacheInfo {
1682        num: 0xC2,
1683        typ: CacheInfoType::DTLB,
1684    },
1685    CacheInfo {
1686        num: 0xCA,
1687        typ: CacheInfoType::STLB,
1688    },
1689    CacheInfo {
1690        num: 0xD0,
1691        typ: CacheInfoType::Cache,
1692    },
1693    CacheInfo {
1694        num: 0xD1,
1695        typ: CacheInfoType::Cache,
1696    },
1697    CacheInfo {
1698        num: 0xD2,
1699        typ: CacheInfoType::Cache,
1700    },
1701    CacheInfo {
1702        num: 0xD6,
1703        typ: CacheInfoType::Cache,
1704    },
1705    CacheInfo {
1706        num: 0xD7,
1707        typ: CacheInfoType::Cache,
1708    },
1709    CacheInfo {
1710        num: 0xD8,
1711        typ: CacheInfoType::Cache,
1712    },
1713    CacheInfo {
1714        num: 0xDC,
1715        typ: CacheInfoType::Cache,
1716    },
1717    CacheInfo {
1718        num: 0xDD,
1719        typ: CacheInfoType::Cache,
1720    },
1721    CacheInfo {
1722        num: 0xDE,
1723        typ: CacheInfoType::Cache,
1724    },
1725    CacheInfo {
1726        num: 0xE2,
1727        typ: CacheInfoType::Cache,
1728    },
1729    CacheInfo {
1730        num: 0xE3,
1731        typ: CacheInfoType::Cache,
1732    },
1733    CacheInfo {
1734        num: 0xE4,
1735        typ: CacheInfoType::Cache,
1736    },
1737    CacheInfo {
1738        num: 0xEA,
1739        typ: CacheInfoType::Cache,
1740    },
1741    CacheInfo {
1742        num: 0xEB,
1743        typ: CacheInfoType::Cache,
1744    },
1745    CacheInfo {
1746        num: 0xEC,
1747        typ: CacheInfoType::Cache,
1748    },
1749    CacheInfo {
1750        num: 0xF0,
1751        typ: CacheInfoType::Prefetch,
1752    },
1753    CacheInfo {
1754        num: 0xF1,
1755        typ: CacheInfoType::Prefetch,
1756    },
1757    CacheInfo {
1758        num: 0xFE,
1759        typ: CacheInfoType::General,
1760    },
1761    CacheInfo {
1762        num: 0xFF,
1763        typ: CacheInfoType::General,
1764    },
1765];
1766
1767/// Processor Serial Number (LEAF=0x3).
1768///
1769/// # Deprecated
1770///
1771/// Processor serial number (PSN) is not supported in the Pentium 4 processor or
1772/// later. On all models, use the PSN flag (returned using CPUID) to check for
1773/// PSN support before accessing the feature.
1774///
1775/// # Platforms
1776/// ❌ AMD ✅ Intel
1777#[derive(PartialEq, Eq)]
1778pub struct ProcessorSerial {
1779    /// Lower bits
1780    ecx: u32,
1781    /// Middle bits
1782    edx: u32,
1783    /// Upper bits (come from leaf 0x1)
1784    eax: u32,
1785}
1786
1787impl ProcessorSerial {
1788    /// Bits 00-31 of 96 bit processor serial number.
1789    ///
1790    /// (Available in Pentium III processor only; otherwise, the value in this register is reserved.)
1791    pub fn serial_lower(&self) -> u32 {
1792        self.ecx
1793    }
1794
1795    /// Bits 32-63 of 96 bit processor serial number.
1796    ///
1797    /// (Available in Pentium III processor only; otherwise, the value in this register is reserved.)
1798    pub fn serial_middle(&self) -> u32 {
1799        self.edx
1800    }
1801
1802    /// Bits 64-96 of 96 bit processor serial number.
1803    pub fn serial_upper(&self) -> u32 {
1804        self.eax
1805    }
1806
1807    /// Combination of bits 00-31 and 32-63 of 96 bit processor serial number.
1808    pub fn serial(&self) -> u64 {
1809        (self.serial_lower() as u64) | (self.serial_middle() as u64) << 32
1810    }
1811
1812    /// 96 bit processor serial number.
1813    pub fn serial_all(&self) -> u128 {
1814        (self.serial_lower() as u128)
1815            | ((self.serial_middle() as u128) << 32)
1816            | ((self.serial_upper() as u128) << 64)
1817    }
1818}
1819
1820impl Debug for ProcessorSerial {
1821    fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
1822        f.debug_struct("ProcessorSerial")
1823            .field("serial_lower", &self.serial_lower())
1824            .field("serial_middle", &self.serial_middle())
1825            .finish()
1826    }
1827}
1828
1829/// Processor and Processor Feature Identifiers (LEAF=0x01).
1830///
1831/// # Platforms
1832/// ✅ AMD ✅ Intel
1833pub struct FeatureInfo {
1834    vendor: Vendor,
1835    eax: u32,
1836    ebx: u32,
1837    edx_ecx: FeatureInfoFlags,
1838}
1839
1840impl FeatureInfo {
1841    /// Version Information: Extended Family
1842    pub fn extended_family_id(&self) -> u8 {
1843        get_bits(self.eax, 20, 27) as u8
1844    }
1845
1846    /// Version Information: Extended Model
1847    pub fn extended_model_id(&self) -> u8 {
1848        get_bits(self.eax, 16, 19) as u8
1849    }
1850
1851    /// Version Information: Family
1852    pub fn base_family_id(&self) -> u8 {
1853        get_bits(self.eax, 8, 11) as u8
1854    }
1855
1856    /// Version Information: Model
1857    pub fn base_model_id(&self) -> u8 {
1858        get_bits(self.eax, 4, 7) as u8
1859    }
1860
1861    pub fn family_id(&self) -> u8 {
1862        let base_family_id = self.base_family_id();
1863        let extended_family_id = self.extended_family_id();
1864        let just_use_base = (self.vendor == Vendor::Amd && base_family_id < 0xf)
1865            || (self.vendor == Vendor::Intel && base_family_id != 0xf);
1866
1867        if just_use_base {
1868            base_family_id
1869        } else {
1870            base_family_id + extended_family_id
1871        }
1872    }
1873
1874    pub fn model_id(&self) -> u8 {
1875        let base_family_id = self.base_family_id();
1876        let base_model_id = self.base_model_id();
1877        let extended_model_id = self.extended_model_id();
1878        let just_use_base = (self.vendor == Vendor::Amd && base_family_id < 0xf)
1879            || (self.vendor == Vendor::Intel && base_family_id != 0xf && base_family_id != 0x6);
1880
1881        if just_use_base {
1882            base_model_id
1883        } else {
1884            (extended_model_id << 4) | base_model_id
1885        }
1886    }
1887
1888    /// Version Information: Stepping ID
1889    pub fn stepping_id(&self) -> u8 {
1890        get_bits(self.eax, 0, 3) as u8
1891    }
1892
1893    /// Brand Index
1894    pub fn brand_index(&self) -> u8 {
1895        get_bits(self.ebx, 0, 7) as u8
1896    }
1897
1898    /// CLFLUSH line size (Value ∗ 8 = cache line size in bytes)
1899    pub fn cflush_cache_line_size(&self) -> u8 {
1900        get_bits(self.ebx, 8, 15) as u8
1901    }
1902
1903    /// Initial APIC ID
1904    pub fn initial_local_apic_id(&self) -> u8 {
1905        get_bits(self.ebx, 24, 31) as u8
1906    }
1907
1908    /// Maximum number of addressable IDs for logical processors in this physical package.
1909    pub fn max_logical_processor_ids(&self) -> u8 {
1910        get_bits(self.ebx, 16, 23) as u8
1911    }
1912
1913    check_flag!(
1914        doc = "Streaming SIMD Extensions 3 (SSE3). A value of 1 indicates the processor \
1915               supports this technology.",
1916        has_sse3,
1917        edx_ecx,
1918        FeatureInfoFlags::SSE3
1919    );
1920
1921    check_flag!(
1922        doc = "PCLMULQDQ. A value of 1 indicates the processor supports the PCLMULQDQ \
1923               instruction",
1924        has_pclmulqdq,
1925        edx_ecx,
1926        FeatureInfoFlags::PCLMULQDQ
1927    );
1928
1929    check_flag!(
1930        doc = "64-bit DS Area. A value of 1 indicates the processor supports DS area \
1931               using 64-bit layout",
1932        has_ds_area,
1933        edx_ecx,
1934        FeatureInfoFlags::DTES64
1935    );
1936
1937    check_flag!(
1938        doc = "MONITOR/MWAIT. A value of 1 indicates the processor supports this feature.",
1939        has_monitor_mwait,
1940        edx_ecx,
1941        FeatureInfoFlags::MONITOR
1942    );
1943
1944    check_flag!(
1945        doc = "CPL Qualified Debug Store. A value of 1 indicates the processor supports \
1946               the extensions to the  Debug Store feature to allow for branch message \
1947               storage qualified by CPL.",
1948        has_cpl,
1949        edx_ecx,
1950        FeatureInfoFlags::DSCPL
1951    );
1952
1953    check_flag!(
1954        doc = "Virtual Machine Extensions. A value of 1 indicates that the processor \
1955               supports this technology.",
1956        has_vmx,
1957        edx_ecx,
1958        FeatureInfoFlags::VMX
1959    );
1960
1961    check_flag!(
1962        doc = "Safer Mode Extensions. A value of 1 indicates that the processor supports \
1963               this technology. See Chapter 5, Safer Mode Extensions Reference.",
1964        has_smx,
1965        edx_ecx,
1966        FeatureInfoFlags::SMX
1967    );
1968
1969    check_flag!(
1970        doc = "Enhanced Intel SpeedStep® technology. A value of 1 indicates that the \
1971               processor supports this technology.",
1972        has_eist,
1973        edx_ecx,
1974        FeatureInfoFlags::EIST
1975    );
1976
1977    check_flag!(
1978        doc = "Thermal Monitor 2. A value of 1 indicates whether the processor supports \
1979               this technology.",
1980        has_tm2,
1981        edx_ecx,
1982        FeatureInfoFlags::TM2
1983    );
1984
1985    check_flag!(
1986        doc = "A value of 1 indicates the presence of the Supplemental Streaming SIMD \
1987               Extensions 3 (SSSE3). A value of 0 indicates the instruction extensions \
1988               are not present in the processor",
1989        has_ssse3,
1990        edx_ecx,
1991        FeatureInfoFlags::SSSE3
1992    );
1993
1994    check_flag!(
1995        doc = "L1 Context ID. A value of 1 indicates the L1 data cache mode can be set \
1996               to either adaptive mode or shared mode. A value of 0 indicates this \
1997               feature is not supported. See definition of the IA32_MISC_ENABLE MSR Bit \
1998               24 (L1 Data Cache Context Mode) for details.",
1999        has_cnxtid,
2000        edx_ecx,
2001        FeatureInfoFlags::CNXTID
2002    );
2003
2004    check_flag!(
2005        doc = "A value of 1 indicates the processor supports FMA extensions using YMM \
2006               state.",
2007        has_fma,
2008        edx_ecx,
2009        FeatureInfoFlags::FMA
2010    );
2011
2012    check_flag!(
2013        doc = "CMPXCHG16B Available. A value of 1 indicates that the feature is \
2014               available. See the CMPXCHG8B/CMPXCHG16B Compare and Exchange Bytes \
2015               section. 14",
2016        has_cmpxchg16b,
2017        edx_ecx,
2018        FeatureInfoFlags::CMPXCHG16B
2019    );
2020
2021    check_flag!(
2022        doc = "Perfmon and Debug Capability: A value of 1 indicates the processor \
2023               supports the performance   and debug feature indication MSR \
2024               IA32_PERF_CAPABILITIES.",
2025        has_pdcm,
2026        edx_ecx,
2027        FeatureInfoFlags::PDCM
2028    );
2029
2030    check_flag!(
2031        doc = "Process-context identifiers. A value of 1 indicates that the processor \
2032               supports PCIDs and the software may set CR4.PCIDE to 1.",
2033        has_pcid,
2034        edx_ecx,
2035        FeatureInfoFlags::PCID
2036    );
2037
2038    check_flag!(
2039        doc = "A value of 1 indicates the processor supports the ability to prefetch \
2040               data from a memory mapped device.",
2041        has_dca,
2042        edx_ecx,
2043        FeatureInfoFlags::DCA
2044    );
2045
2046    check_flag!(
2047        doc = "A value of 1 indicates that the processor supports SSE4.1.",
2048        has_sse41,
2049        edx_ecx,
2050        FeatureInfoFlags::SSE41
2051    );
2052
2053    check_flag!(
2054        doc = "A value of 1 indicates that the processor supports SSE4.2.",
2055        has_sse42,
2056        edx_ecx,
2057        FeatureInfoFlags::SSE42
2058    );
2059
2060    check_flag!(
2061        doc = "A value of 1 indicates that the processor supports x2APIC feature.",
2062        has_x2apic,
2063        edx_ecx,
2064        FeatureInfoFlags::X2APIC
2065    );
2066
2067    check_flag!(
2068        doc = "A value of 1 indicates that the processor supports MOVBE instruction.",
2069        has_movbe,
2070        edx_ecx,
2071        FeatureInfoFlags::MOVBE
2072    );
2073
2074    check_flag!(
2075        doc = "A value of 1 indicates that the processor supports the POPCNT instruction.",
2076        has_popcnt,
2077        edx_ecx,
2078        FeatureInfoFlags::POPCNT
2079    );
2080
2081    check_flag!(
2082        doc = "A value of 1 indicates that the processors local APIC timer supports \
2083               one-shot operation using a TSC deadline value.",
2084        has_tsc_deadline,
2085        edx_ecx,
2086        FeatureInfoFlags::TSC_DEADLINE
2087    );
2088
2089    check_flag!(
2090        doc = "A value of 1 indicates that the processor supports the AESNI instruction \
2091               extensions.",
2092        has_aesni,
2093        edx_ecx,
2094        FeatureInfoFlags::AESNI
2095    );
2096
2097    check_flag!(
2098        doc = "A value of 1 indicates that the processor supports the XSAVE/XRSTOR \
2099               processor extended states feature, the XSETBV/XGETBV instructions, and \
2100               XCR0.",
2101        has_xsave,
2102        edx_ecx,
2103        FeatureInfoFlags::XSAVE
2104    );
2105
2106    check_flag!(
2107        doc = "A value of 1 indicates that the OS has enabled XSETBV/XGETBV instructions \
2108               to access XCR0, and support for processor extended state management using \
2109               XSAVE/XRSTOR.",
2110        has_oxsave,
2111        edx_ecx,
2112        FeatureInfoFlags::OSXSAVE
2113    );
2114
2115    check_flag!(
2116        doc = "A value of 1 indicates the processor supports the AVX instruction \
2117               extensions.",
2118        has_avx,
2119        edx_ecx,
2120        FeatureInfoFlags::AVX
2121    );
2122
2123    check_flag!(
2124        doc = "A value of 1 indicates that processor supports 16-bit floating-point \
2125               conversion instructions.",
2126        has_f16c,
2127        edx_ecx,
2128        FeatureInfoFlags::F16C
2129    );
2130
2131    check_flag!(
2132        doc = "A value of 1 indicates that processor supports RDRAND instruction.",
2133        has_rdrand,
2134        edx_ecx,
2135        FeatureInfoFlags::RDRAND
2136    );
2137
2138    check_flag!(
2139        doc = "A value of 1 indicates the indicates the presence of a hypervisor.",
2140        has_hypervisor,
2141        edx_ecx,
2142        FeatureInfoFlags::HYPERVISOR
2143    );
2144
2145    check_flag!(
2146        doc = "Floating Point Unit On-Chip. The processor contains an x87 FPU.",
2147        has_fpu,
2148        edx_ecx,
2149        FeatureInfoFlags::FPU
2150    );
2151
2152    check_flag!(
2153        doc = "Virtual 8086 Mode Enhancements. Virtual 8086 mode enhancements, including \
2154               CR4.VME for controlling the feature, CR4.PVI for protected mode virtual \
2155               interrupts, software interrupt indirection, expansion of the TSS with the \
2156               software indirection bitmap, and EFLAGS.VIF and EFLAGS.VIP flags.",
2157        has_vme,
2158        edx_ecx,
2159        FeatureInfoFlags::VME
2160    );
2161
2162    check_flag!(
2163        doc = "Debugging Extensions. Support for I/O breakpoints, including CR4.DE for \
2164               controlling the feature, and optional trapping of accesses to DR4 and DR5.",
2165        has_de,
2166        edx_ecx,
2167        FeatureInfoFlags::DE
2168    );
2169
2170    check_flag!(
2171        doc = "Page Size Extension. Large pages of size 4 MByte are supported, including \
2172               CR4.PSE for controlling the feature, the defined dirty bit in PDE (Page \
2173               Directory Entries), optional reserved bit trapping in CR3, PDEs, and PTEs.",
2174        has_pse,
2175        edx_ecx,
2176        FeatureInfoFlags::PSE
2177    );
2178
2179    check_flag!(
2180        doc = "Time Stamp Counter. The RDTSC instruction is supported, including CR4.TSD \
2181               for controlling privilege.",
2182        has_tsc,
2183        edx_ecx,
2184        FeatureInfoFlags::TSC
2185    );
2186
2187    check_flag!(
2188        doc = "Model Specific Registers RDMSR and WRMSR Instructions. The RDMSR and \
2189               WRMSR instructions are supported. Some of the MSRs are implementation \
2190               dependent.",
2191        has_msr,
2192        edx_ecx,
2193        FeatureInfoFlags::MSR
2194    );
2195
2196    check_flag!(
2197        doc = "Physical Address Extension. Physical addresses greater than 32 bits are \
2198               supported: extended page table entry formats, an extra level in the page \
2199               translation tables is defined, 2-MByte pages are supported instead of 4 \
2200               Mbyte pages if PAE bit is 1.",
2201        has_pae,
2202        edx_ecx,
2203        FeatureInfoFlags::PAE
2204    );
2205
2206    check_flag!(
2207        doc = "Machine Check Exception. Exception 18 is defined for Machine Checks, \
2208               including CR4.MCE for controlling the feature. This feature does not \
2209               define the model-specific implementations of machine-check error logging, \
2210               reporting, and processor shutdowns. Machine Check exception handlers may \
2211               have to depend on processor version to do model specific processing of \
2212               the exception, or test for the presence of the Machine Check feature.",
2213        has_mce,
2214        edx_ecx,
2215        FeatureInfoFlags::MCE
2216    );
2217
2218    check_flag!(
2219        doc = "CMPXCHG8B Instruction. The compare-and-exchange 8 bytes (64 bits) \
2220               instruction is supported (implicitly locked and atomic).",
2221        has_cmpxchg8b,
2222        edx_ecx,
2223        FeatureInfoFlags::CX8
2224    );
2225
2226    check_flag!(
2227        doc = "APIC On-Chip. The processor contains an Advanced Programmable Interrupt \
2228               Controller (APIC), responding to memory mapped commands in the physical \
2229               address range FFFE0000H to FFFE0FFFH (by default - some processors permit \
2230               the APIC to be relocated).",
2231        has_apic,
2232        edx_ecx,
2233        FeatureInfoFlags::APIC
2234    );
2235
2236    check_flag!(
2237        doc = "SYSENTER and SYSEXIT Instructions. The SYSENTER and SYSEXIT and \
2238               associated MSRs are supported.",
2239        has_sysenter_sysexit,
2240        edx_ecx,
2241        FeatureInfoFlags::SEP
2242    );
2243
2244    check_flag!(
2245        doc = "Memory Type Range Registers. MTRRs are supported. The MTRRcap MSR \
2246               contains feature bits that describe what memory types are supported, how \
2247               many variable MTRRs are supported, and whether fixed MTRRs are supported.",
2248        has_mtrr,
2249        edx_ecx,
2250        FeatureInfoFlags::MTRR
2251    );
2252
2253    check_flag!(
2254        doc = "Page Global Bit. The global bit is supported in paging-structure entries \
2255               that map a page, indicating TLB entries that are common to different \
2256               processes and need not be flushed. The CR4.PGE bit controls this feature.",
2257        has_pge,
2258        edx_ecx,
2259        FeatureInfoFlags::PGE
2260    );
2261
2262    check_flag!(
2263        doc = "Machine Check Architecture. A value of 1 indicates the Machine Check \
2264               Architecture of reporting machine errors is supported. The MCG_CAP MSR \
2265               contains feature bits describing how many banks of error reporting MSRs \
2266               are supported.",
2267        has_mca,
2268        edx_ecx,
2269        FeatureInfoFlags::MCA
2270    );
2271
2272    check_flag!(
2273        doc = "Conditional Move Instructions. The conditional move instruction CMOV is \
2274               supported. In addition, if x87 FPU is present as indicated by the \
2275               CPUID.FPU feature bit, then the FCOMI and FCMOV instructions are supported",
2276        has_cmov,
2277        edx_ecx,
2278        FeatureInfoFlags::CMOV
2279    );
2280
2281    check_flag!(
2282        doc = "Page Attribute Table. Page Attribute Table is supported. This feature \
2283               augments the Memory Type Range Registers (MTRRs), allowing an operating \
2284               system to specify attributes of memory accessed through a linear address \
2285               on a 4KB granularity.",
2286        has_pat,
2287        edx_ecx,
2288        FeatureInfoFlags::PAT
2289    );
2290
2291    check_flag!(
2292        doc = "36-Bit Page Size Extension. 4-MByte pages addressing physical memory \
2293               beyond 4 GBytes are supported with 32-bit paging. This feature indicates \
2294               that upper bits of the physical address of a 4-MByte page are encoded in \
2295               bits 20:13 of the page-directory entry. Such physical addresses are \
2296               limited by MAXPHYADDR and may be up to 40 bits in size.",
2297        has_pse36,
2298        edx_ecx,
2299        FeatureInfoFlags::PSE36
2300    );
2301
2302    check_flag!(
2303        doc = "Processor Serial Number. The processor supports the 96-bit processor \
2304               identification number feature and the feature is enabled.",
2305        has_psn,
2306        edx_ecx,
2307        FeatureInfoFlags::PSN
2308    );
2309
2310    check_flag!(
2311        doc = "CLFLUSH Instruction. CLFLUSH Instruction is supported.",
2312        has_clflush,
2313        edx_ecx,
2314        FeatureInfoFlags::CLFSH
2315    );
2316
2317    check_flag!(
2318        doc = "Debug Store. The processor supports the ability to write debug \
2319               information into a memory resident buffer. This feature is used by the \
2320               branch trace store (BTS) and processor event-based sampling (PEBS) \
2321               facilities (see Chapter 23, Introduction to Virtual-Machine Extensions, \
2322               in the Intel® 64 and IA-32 Architectures Software Developers Manual, \
2323               Volume 3C).",
2324        has_ds,
2325        edx_ecx,
2326        FeatureInfoFlags::DS
2327    );
2328
2329    check_flag!(
2330        doc = "Thermal Monitor and Software Controlled Clock Facilities. The processor \
2331               implements internal MSRs that allow processor temperature to be monitored \
2332               and processor performance to be modulated in predefined duty cycles under \
2333               software control.",
2334        has_acpi,
2335        edx_ecx,
2336        FeatureInfoFlags::ACPI
2337    );
2338
2339    check_flag!(
2340        doc = "Intel MMX Technology. The processor supports the Intel MMX technology.",
2341        has_mmx,
2342        edx_ecx,
2343        FeatureInfoFlags::MMX
2344    );
2345
2346    check_flag!(
2347        doc = "FXSAVE and FXRSTOR Instructions. The FXSAVE and FXRSTOR instructions are \
2348               supported for fast save and restore of the floating point context. \
2349               Presence of this bit also indicates that CR4.OSFXSR is available for an \
2350               operating system to indicate that it supports the FXSAVE and FXRSTOR \
2351               instructions.",
2352        has_fxsave_fxstor,
2353        edx_ecx,
2354        FeatureInfoFlags::FXSR
2355    );
2356
2357    check_flag!(
2358        doc = "SSE. The processor supports the SSE extensions.",
2359        has_sse,
2360        edx_ecx,
2361        FeatureInfoFlags::SSE
2362    );
2363
2364    check_flag!(
2365        doc = "SSE2. The processor supports the SSE2 extensions.",
2366        has_sse2,
2367        edx_ecx,
2368        FeatureInfoFlags::SSE2
2369    );
2370
2371    check_flag!(
2372        doc = "Self Snoop. The processor supports the management of conflicting memory \
2373               types by performing a snoop of its own cache structure for transactions \
2374               issued to the bus.",
2375        has_ss,
2376        edx_ecx,
2377        FeatureInfoFlags::SS
2378    );
2379
2380    check_flag!(
2381        doc = "Max APIC IDs reserved field is Valid. A value of 0 for HTT indicates \
2382               there is only a single logical processor in the package and software \
2383               should assume only a single APIC ID is reserved.  A value of 1 for HTT \
2384               indicates the value in CPUID.1.EBX\\[23:16\\] (the Maximum number of \
2385               addressable IDs for logical processors in this package) is valid for the \
2386               package.",
2387        has_htt,
2388        edx_ecx,
2389        FeatureInfoFlags::HTT
2390    );
2391
2392    check_flag!(
2393        doc = "Thermal Monitor. The processor implements the thermal monitor automatic \
2394               thermal control circuitry (TCC).",
2395        has_tm,
2396        edx_ecx,
2397        FeatureInfoFlags::TM
2398    );
2399
2400    check_flag!(
2401        doc = "Pending Break Enable. The processor supports the use of the FERR#/PBE# \
2402               pin when the processor is in the stop-clock state (STPCLK# is asserted) \
2403               to signal the processor that an interrupt is pending and that the \
2404               processor should return to normal operation to handle the interrupt. Bit \
2405               10 (PBE enable) in the IA32_MISC_ENABLE MSR enables this capability.",
2406        has_pbe,
2407        edx_ecx,
2408        FeatureInfoFlags::PBE
2409    );
2410}
2411
2412impl Debug for FeatureInfo {
2413    fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
2414        f.debug_struct("FeatureInfo")
2415            .field("extended_family_id", &self.extended_family_id())
2416            .field("extended_model_id", &self.extended_model_id())
2417            .field("family_id", &self.family_id())
2418            .field("model_id", &self.model_id())
2419            .field("stepping_id", &self.stepping_id())
2420            .field("brand_index", &self.brand_index())
2421            .field("cflush_cache_line_size", &self.cflush_cache_line_size())
2422            .field("initial_local_apic_id", &self.initial_local_apic_id())
2423            .field(
2424                "max_logical_processor_ids",
2425                &self.max_logical_processor_ids(),
2426            )
2427            .field("edx_ecx", &self.edx_ecx)
2428            .finish()
2429    }
2430}
2431
2432bitflags! {
2433    #[repr(transparent)]
2434    #[derive(Debug, Clone, Copy, PartialEq, Eq)]
2435    struct FeatureInfoFlags: u64 {
2436        // ECX flags
2437
2438        /// Streaming SIMD Extensions 3 (SSE3). A value of 1 indicates the processor supports this technology.
2439        const SSE3 = 1 << 0;
2440        /// PCLMULQDQ. A value of 1 indicates the processor supports the PCLMULQDQ instruction
2441        const PCLMULQDQ = 1 << 1;
2442        /// 64-bit DS Area. A value of 1 indicates the processor supports DS area using 64-bit layout
2443        const DTES64 = 1 << 2;
2444        /// MONITOR/MWAIT. A value of 1 indicates the processor supports this feature.
2445        const MONITOR = 1 << 3;
2446        /// 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.
2447        const DSCPL = 1 << 4;
2448        /// Virtual Machine Extensions. A value of 1 indicates that the processor supports this technology.
2449        const VMX = 1 << 5;
2450        /// Safer Mode Extensions. A value of 1 indicates that the processor supports this technology. See Chapter 5, Safer Mode Extensions Reference.
2451        const SMX = 1 << 6;
2452        /// Enhanced Intel SpeedStep® technology. A value of 1 indicates that the processor supports this technology.
2453        const EIST = 1 << 7;
2454        /// Thermal Monitor 2. A value of 1 indicates whether the processor supports this technology.
2455        const TM2 = 1 << 8;
2456        /// 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
2457        const SSSE3 = 1 << 9;
2458        /// 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.
2459        const CNXTID = 1 << 10;
2460        /// A value of 1 indicates the processor supports FMA extensions using YMM state.
2461        const FMA = 1 << 12;
2462        /// CMPXCHG16B Available. A value of 1 indicates that the feature is available. See the CMPXCHG8B/CMPXCHG16B Compare and Exchange Bytes section. 14
2463        const CMPXCHG16B = 1 << 13;
2464        /// Perfmon and Debug Capability: A value of 1 indicates the processor supports the performance   and debug feature indication MSR IA32_PERF_CAPABILITIES.
2465        const PDCM = 1 << 15;
2466        /// Process-context identifiers. A value of 1 indicates that the processor supports PCIDs and the software may set CR4.PCIDE to 1.
2467        const PCID = 1 << 17;
2468        /// A value of 1 indicates the processor supports the ability to prefetch data from a memory mapped device.
2469        const DCA = 1 << 18;
2470        /// A value of 1 indicates that the processor supports SSE4.1.
2471        const SSE41 = 1 << 19;
2472        /// A value of 1 indicates that the processor supports SSE4.2.
2473        const SSE42 = 1 << 20;
2474        /// A value of 1 indicates that the processor supports x2APIC feature.
2475        const X2APIC = 1 << 21;
2476        /// A value of 1 indicates that the processor supports MOVBE instruction.
2477        const MOVBE = 1 << 22;
2478        /// A value of 1 indicates that the processor supports the POPCNT instruction.
2479        const POPCNT = 1 << 23;
2480        /// A value of 1 indicates that the processors local APIC timer supports one-shot operation using a TSC deadline value.
2481        const TSC_DEADLINE = 1 << 24;
2482        /// A value of 1 indicates that the processor supports the AESNI instruction extensions.
2483        const AESNI = 1 << 25;
2484        /// A value of 1 indicates that the processor supports the XSAVE/XRSTOR processor extended states feature, the XSETBV/XGETBV instructions, and XCR0.
2485        const XSAVE = 1 << 26;
2486        /// 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.
2487        const OSXSAVE = 1 << 27;
2488        /// A value of 1 indicates the processor supports the AVX instruction extensions.
2489        const AVX = 1 << 28;
2490        /// A value of 1 indicates that processor supports 16-bit floating-point conversion instructions.
2491        const F16C = 1 << 29;
2492        /// A value of 1 indicates that processor supports RDRAND instruction.
2493        const RDRAND = 1 << 30;
2494        /// A value of 1 indicates the indicates the presence of a hypervisor.
2495        const HYPERVISOR = 1 << 31;
2496
2497
2498        // EDX flags
2499
2500        /// Floating Point Unit On-Chip. The processor contains an x87 FPU.
2501        const FPU = 1 << 32;
2502        /// 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.
2503        const VME = 1 << (32 + 1);
2504        /// Debugging Extensions. Support for I/O breakpoints, including CR4.DE for controlling the feature, and optional trapping of accesses to DR4 and DR5.
2505        const DE = 1 << (32 + 2);
2506        /// 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.
2507        const PSE = 1 << (32 + 3);
2508        /// Time Stamp Counter. The RDTSC instruction is supported, including CR4.TSD for controlling privilege.
2509        const TSC = 1 << (32 + 4);
2510        /// Model Specific Registers RDMSR and WRMSR Instructions. The RDMSR and WRMSR instructions are supported. Some of the MSRs are implementation dependent.
2511        const MSR = 1 << (32 + 5);
2512        /// 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.
2513        const PAE = 1 << (32 + 6);
2514        /// 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.
2515        const MCE = 1 << (32 + 7);
2516        /// CMPXCHG8B Instruction. The compare-and-exchange 8 bytes (64 bits) instruction is supported (implicitly locked and atomic).
2517        const CX8 = 1 << (32 + 8);
2518        /// 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).
2519        const APIC = 1 << (32 + 9);
2520        /// SYSENTER and SYSEXIT Instructions. The SYSENTER and SYSEXIT and associated MSRs are supported.
2521        const SEP = 1 << (32 + 11);
2522        /// 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.
2523        const MTRR = 1 << (32 + 12);
2524        /// 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.
2525        const PGE = 1 << (32 + 13);
2526        /// 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.
2527        const MCA = 1 << (32 + 14);
2528        /// 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
2529        const CMOV = 1 << (32 + 15);
2530        /// 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.
2531        const PAT = 1 << (32 + 16);
2532        /// 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.
2533        const PSE36 = 1 << (32 + 17);
2534        /// Processor Serial Number. The processor supports the 96-bit processor identification number feature and the feature is enabled.
2535        const PSN = 1 << (32 + 18);
2536        /// CLFLUSH Instruction. CLFLUSH Instruction is supported.
2537        const CLFSH = 1 << (32 + 19);
2538        /// 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).
2539        const DS = 1 << (32 + 21);
2540        /// 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.
2541        const ACPI = 1 << (32 + 22);
2542        /// Intel MMX Technology. The processor supports the Intel MMX technology.
2543        const MMX = 1 << (32 + 23);
2544        /// 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.
2545        const FXSR = 1 << (32 + 24);
2546        /// SSE. The processor supports the SSE extensions.
2547        const SSE = 1 << (32 + 25);
2548        /// SSE2. The processor supports the SSE2 extensions.
2549        const SSE2 = 1 << (32 + 26);
2550        /// 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.
2551        const SS = 1 << (32 + 27);
2552        /// 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.
2553        const HTT = 1 << (32 + 28);
2554        /// Thermal Monitor. The processor implements the thermal monitor automatic thermal control circuitry (TCC).
2555        const TM = 1 << (32 + 29);
2556        /// 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.
2557        const PBE = 1 << (32 + 31);
2558    }
2559}
2560
2561/// Iterator over caches (LEAF=0x04).
2562///
2563/// Yields a [CacheParameter] for each cache.
2564///
2565/// # Platforms
2566/// 🟡 AMD ✅ Intel
2567#[derive(Clone, Copy)]
2568pub struct CacheParametersIter<R: CpuIdReader> {
2569    read: R,
2570    leaf: u32,
2571    current: u32,
2572}
2573
2574impl<R: CpuIdReader> Iterator for CacheParametersIter<R> {
2575    type Item = CacheParameter;
2576
2577    /// Iterate over all cache info subleafs for this CPU.
2578    ///
2579    /// # Note
2580    /// cpuid is called every-time we advance the iterator to get information
2581    /// about the next cache.
2582    fn next(&mut self) -> Option<CacheParameter> {
2583        let res = self.read.cpuid2(self.leaf, self.current);
2584        let cp = CacheParameter {
2585            eax: res.eax,
2586            ebx: res.ebx,
2587            ecx: res.ecx,
2588            edx: res.edx,
2589        };
2590
2591        match cp.cache_type() {
2592            CacheType::Null => None,
2593            CacheType::Reserved => None,
2594            _ => {
2595                self.current += 1;
2596                Some(cp)
2597            }
2598        }
2599    }
2600}
2601
2602impl<R: CpuIdReader> Debug for CacheParametersIter<R> {
2603    fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
2604        let mut debug = f.debug_list();
2605        self.clone().for_each(|ref item| {
2606            debug.entry(item);
2607        });
2608        debug.finish()
2609    }
2610}
2611
2612/// Information about an individual cache in the hierarchy.
2613///
2614/// # Platforms
2615/// 🟡 AMD ✅ Intel
2616#[derive(Copy, Clone, Eq, PartialEq)]
2617pub struct CacheParameter {
2618    eax: u32,
2619    ebx: u32,
2620    ecx: u32,
2621    edx: u32,
2622}
2623
2624/// Info about a what a given cache caches (instructions, data, etc.)
2625#[derive(PartialEq, Eq, Debug)]
2626pub enum CacheType {
2627    /// Null - No more caches
2628    Null = 0,
2629    /// Data cache
2630    Data,
2631    /// Instruction cache
2632    Instruction,
2633    /// Data and Instruction cache
2634    Unified,
2635    /// 4-31 = Reserved
2636    Reserved,
2637}
2638
2639impl fmt::Display for CacheType {
2640    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2641        let typ = match self {
2642            CacheType::Null => "Null",
2643            CacheType::Data => "Data",
2644            CacheType::Instruction => "Instruction",
2645            CacheType::Unified => "Unified",
2646            CacheType::Reserved => "Reserved",
2647        };
2648
2649        f.write_str(typ)
2650    }
2651}
2652
2653impl CacheParameter {
2654    /// Cache Type
2655    ///
2656    /// # Platforms
2657    /// ✅ AMD ✅ Intel
2658    pub fn cache_type(&self) -> CacheType {
2659        let typ = get_bits(self.eax, 0, 4) as u8;
2660        match typ {
2661            0 => CacheType::Null,
2662            1 => CacheType::Data,
2663            2 => CacheType::Instruction,
2664            3 => CacheType::Unified,
2665            _ => CacheType::Reserved,
2666        }
2667    }
2668
2669    /// Cache Level (starts at 1)
2670    ///
2671    /// # Platforms
2672    /// ✅ AMD ✅ Intel
2673    pub fn level(&self) -> u8 {
2674        get_bits(self.eax, 5, 7) as u8
2675    }
2676
2677    /// Self Initializing cache level (does not need SW initialization).
2678    ///
2679    /// # Platforms
2680    /// ✅ AMD ✅ Intel
2681    pub fn is_self_initializing(&self) -> bool {
2682        get_bits(self.eax, 8, 8) == 1
2683    }
2684
2685    /// Fully Associative cache
2686    ///
2687    /// # Platforms
2688    /// ✅ AMD ✅ Intel
2689    pub fn is_fully_associative(&self) -> bool {
2690        get_bits(self.eax, 9, 9) == 1
2691    }
2692
2693    /// Maximum number of addressable IDs for logical processors sharing this cache
2694    ///
2695    /// # Platforms
2696    /// ✅ AMD ✅ Intel
2697    pub fn max_cores_for_cache(&self) -> usize {
2698        (get_bits(self.eax, 14, 25) + 1) as usize
2699    }
2700
2701    /// Maximum number of addressable IDs for processor cores in the physical package
2702    ///
2703    /// # Platforms
2704    /// ❌ AMD ✅ Intel
2705    pub fn max_cores_for_package(&self) -> usize {
2706        (get_bits(self.eax, 26, 31) + 1) as usize
2707    }
2708
2709    /// System Coherency Line Size (Bits 11-00)
2710    ///
2711    /// # Platforms
2712    /// ✅ AMD ✅ Intel
2713    pub fn coherency_line_size(&self) -> usize {
2714        (get_bits(self.ebx, 0, 11) + 1) as usize
2715    }
2716
2717    /// Physical Line partitions (Bits 21-12)
2718    ///
2719    /// # Platforms
2720    /// ✅ AMD ✅ Intel
2721    pub fn physical_line_partitions(&self) -> usize {
2722        (get_bits(self.ebx, 12, 21) + 1) as usize
2723    }
2724
2725    /// Ways of associativity (Bits 31-22)
2726    ///
2727    /// # Platforms
2728    /// ✅ AMD ✅ Intel
2729    pub fn associativity(&self) -> usize {
2730        (get_bits(self.ebx, 22, 31) + 1) as usize
2731    }
2732
2733    /// Number of Sets (Bits 31-00)
2734    ///
2735    /// # Platforms
2736    /// ✅ AMD ✅ Intel
2737    pub fn sets(&self) -> usize {
2738        (self.ecx + 1) as usize
2739    }
2740
2741    /// Write-Back Invalidate/Invalidate (Bit 0)
2742    /// False: WBINVD/INVD from threads sharing this cache acts upon lower level caches for threads sharing this cache.
2743    /// True: WBINVD/INVD is not guaranteed to act upon lower level caches of non-originating threads sharing this cache.
2744    ///
2745    /// # Platforms
2746    /// ✅ AMD ✅ Intel
2747    pub fn is_write_back_invalidate(&self) -> bool {
2748        get_bits(self.edx, 0, 0) == 1
2749    }
2750
2751    /// Cache Inclusiveness (Bit 1)
2752    /// False: Cache is not inclusive of lower cache levels.
2753    /// True: Cache is inclusive of lower cache levels.
2754    ///
2755    /// # Platforms
2756    /// ✅ AMD ✅ Intel
2757    pub fn is_inclusive(&self) -> bool {
2758        get_bits(self.edx, 1, 1) == 1
2759    }
2760
2761    /// Complex Cache Indexing (Bit 2)
2762    /// False: Direct mapped cache.
2763    /// True: A complex function is used to index the cache, potentially using all address bits.
2764    ///
2765    /// # Platforms
2766    /// ❌ AMD ✅ Intel
2767    pub fn has_complex_indexing(&self) -> bool {
2768        get_bits(self.edx, 2, 2) == 1
2769    }
2770}
2771
2772impl Debug for CacheParameter {
2773    fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
2774        f.debug_struct("CacheParameter")
2775            .field("cache_type", &self.cache_type())
2776            .field("level", &self.level())
2777            .field("is_self_initializing", &self.is_self_initializing())
2778            .field("is_fully_associative", &self.is_fully_associative())
2779            .field("max_cores_for_cache", &self.max_cores_for_cache())
2780            .field("max_cores_for_package", &self.max_cores_for_package())
2781            .field("coherency_line_size", &self.coherency_line_size())
2782            .field("physical_line_partitions", &self.physical_line_partitions())
2783            .field("associativity", &self.associativity())
2784            .field("sets", &self.sets())
2785            .field("is_write_back_invalidate", &self.is_write_back_invalidate())
2786            .field("is_inclusive", &self.is_inclusive())
2787            .field("has_complex_indexing", &self.has_complex_indexing())
2788            .finish()
2789    }
2790}
2791
2792/// Information about how monitor/mwait works on this CPU (LEAF=0x05).
2793///
2794/// # Platforms
2795/// 🟡 AMD ✅ Intel
2796#[derive(Eq, PartialEq)]
2797pub struct MonitorMwaitInfo {
2798    eax: u32,
2799    ebx: u32,
2800    ecx: u32,
2801    edx: u32,
2802}
2803
2804impl MonitorMwaitInfo {
2805    /// Smallest monitor-line size in bytes (default is processor's monitor granularity)
2806    ///
2807    /// # Platforms
2808    /// ✅ AMD ✅ Intel
2809    pub fn smallest_monitor_line(&self) -> u16 {
2810        get_bits(self.eax, 0, 15) as u16
2811    }
2812
2813    /// Largest monitor-line size in bytes (default is processor's monitor granularity
2814    ///
2815    /// # Platforms
2816    /// ✅ AMD ✅ Intel
2817    pub fn largest_monitor_line(&self) -> u16 {
2818        get_bits(self.ebx, 0, 15) as u16
2819    }
2820
2821    ///  Enumeration of Monitor-Mwait extensions (beyond EAX and EBX registers) supported
2822    ///
2823    /// # Platforms
2824    /// ✅ AMD ✅ Intel
2825    pub fn extensions_supported(&self) -> bool {
2826        get_bits(self.ecx, 0, 0) == 1
2827    }
2828
2829    ///  Supports treating interrupts as break-event for MWAIT, even when interrupts disabled
2830    ///
2831    /// # Platforms
2832    /// ✅ AMD ✅ Intel
2833    pub fn interrupts_as_break_event(&self) -> bool {
2834        get_bits(self.ecx, 1, 1) == 1
2835    }
2836
2837    /// Number of C0 sub C-states supported using MWAIT (Bits 03 - 00)
2838    ///
2839    /// # Platforms
2840    /// ❌ AMD (undefined/reserved) ✅ Intel
2841    pub fn supported_c0_states(&self) -> u16 {
2842        get_bits(self.edx, 0, 3) as u16
2843    }
2844
2845    /// Number of C1 sub C-states supported using MWAIT (Bits 07 - 04)
2846    ///
2847    /// # Platforms
2848    /// ❌ AMD (undefined/reserved) ✅ Intel
2849    pub fn supported_c1_states(&self) -> u16 {
2850        get_bits(self.edx, 4, 7) as u16
2851    }
2852
2853    /// Number of C2 sub C-states supported using MWAIT (Bits 11 - 08)
2854    ///
2855    /// # Platforms
2856    /// ❌ AMD (undefined/reserved) ✅ Intel
2857    pub fn supported_c2_states(&self) -> u16 {
2858        get_bits(self.edx, 8, 11) as u16
2859    }
2860
2861    /// Number of C3 sub C-states supported using MWAIT (Bits 15 - 12)
2862    ///
2863    /// # Platforms
2864    /// ❌ AMD (undefined/reserved) ✅ Intel
2865    pub fn supported_c3_states(&self) -> u16 {
2866        get_bits(self.edx, 12, 15) as u16
2867    }
2868
2869    /// Number of C4 sub C-states supported using MWAIT (Bits 19 - 16)
2870    ///
2871    /// # Platforms
2872    /// ❌ AMD (undefined/reserved) ✅ Intel
2873    pub fn supported_c4_states(&self) -> u16 {
2874        get_bits(self.edx, 16, 19) as u16
2875    }
2876
2877    /// Number of C5 sub C-states supported using MWAIT (Bits 23 - 20)
2878    ///
2879    /// # Platforms
2880    /// ❌ AMD (undefined/reserved) ✅ Intel
2881    pub fn supported_c5_states(&self) -> u16 {
2882        get_bits(self.edx, 20, 23) as u16
2883    }
2884
2885    /// Number of C6 sub C-states supported using MWAIT (Bits 27 - 24)
2886    ///
2887    /// # Platforms
2888    /// ❌ AMD (undefined/reserved) ✅ Intel
2889    pub fn supported_c6_states(&self) -> u16 {
2890        get_bits(self.edx, 24, 27) as u16
2891    }
2892
2893    /// Number of C7 sub C-states supported using MWAIT (Bits 31 - 28)
2894    ///
2895    /// # Platforms
2896    /// ❌ AMD (undefined/reserved) ✅ Intel
2897    pub fn supported_c7_states(&self) -> u16 {
2898        get_bits(self.edx, 28, 31) as u16
2899    }
2900}
2901
2902impl Debug for MonitorMwaitInfo {
2903    fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
2904        f.debug_struct("MonitorMwaitInfo")
2905            .field("smallest_monitor_line", &self.smallest_monitor_line())
2906            .field("largest_monitor_line", &self.largest_monitor_line())
2907            .field("extensions_supported", &self.extensions_supported())
2908            .field(
2909                "interrupts_as_break_event",
2910                &self.interrupts_as_break_event(),
2911            )
2912            .field("supported_c0_states", &self.supported_c0_states())
2913            .field("supported_c1_states", &self.supported_c1_states())
2914            .field("supported_c2_states", &self.supported_c2_states())
2915            .field("supported_c3_states", &self.supported_c3_states())
2916            .field("supported_c4_states", &self.supported_c4_states())
2917            .field("supported_c5_states", &self.supported_c5_states())
2918            .field("supported_c6_states", &self.supported_c6_states())
2919            .field("supported_c7_states", &self.supported_c7_states())
2920            .finish()
2921    }
2922}
2923
2924/// Query information about thermal and power management features of the CPU (LEAF=0x06).
2925///
2926/// # Platforms
2927/// 🟡 AMD ✅ Intel
2928pub struct ThermalPowerInfo {
2929    eax: ThermalPowerFeaturesEax,
2930    ebx: u32,
2931    ecx: ThermalPowerFeaturesEcx,
2932    _edx: u32,
2933}
2934
2935impl ThermalPowerInfo {
2936    /// Number of Interrupt Thresholds in Digital Thermal Sensor
2937    ///
2938    /// # Platforms
2939    /// ❌ AMD (undefined/reserved) ✅ Intel
2940    pub fn dts_irq_threshold(&self) -> u8 {
2941        get_bits(self.ebx, 0, 3) as u8
2942    }
2943
2944    /// Digital temperature sensor is supported if set.
2945    ///
2946    /// # Platforms
2947    /// ❌ AMD (reserved) ✅ Intel
2948    pub fn has_dts(&self) -> bool {
2949        self.eax.contains(ThermalPowerFeaturesEax::DTS)
2950    }
2951
2952    /// Intel Turbo Boost Technology Available (see description of
2953    /// IA32_MISC_ENABLE\[38\]).
2954    ///
2955    /// # Platforms
2956    /// ❌ AMD (reserved) ✅ Intel
2957    pub fn has_turbo_boost(&self) -> bool {
2958        self.eax.contains(ThermalPowerFeaturesEax::TURBO_BOOST)
2959    }
2960
2961    /// ARAT. APIC-Timer-always-running feature is supported if set.
2962    ///
2963    /// # Platforms
2964    /// ✅ AMD ✅ Intel
2965    pub fn has_arat(&self) -> bool {
2966        self.eax.contains(ThermalPowerFeaturesEax::ARAT)
2967    }
2968
2969    /// PLN. Power limit notification controls are supported if set.
2970    ///
2971    /// # Platforms
2972    /// ❌ AMD (reserved) ✅ Intel
2973    pub fn has_pln(&self) -> bool {
2974        self.eax.contains(ThermalPowerFeaturesEax::PLN)
2975    }
2976
2977    /// ECMD. Clock modulation duty cycle extension is supported if set.
2978    ///
2979    /// # Platforms
2980    /// ❌ AMD (reserved) ✅ Intel
2981    pub fn has_ecmd(&self) -> bool {
2982        self.eax.contains(ThermalPowerFeaturesEax::ECMD)
2983    }
2984
2985    /// PTM. Package thermal management is supported if set.
2986    ///
2987    /// # Platforms
2988    /// ❌ AMD (reserved) ✅ Intel
2989    pub fn has_ptm(&self) -> bool {
2990        self.eax.contains(ThermalPowerFeaturesEax::PTM)
2991    }
2992
2993    /// HWP. HWP base registers (IA32_PM_ENABLE[bit 0], IA32_HWP_CAPABILITIES,
2994    /// IA32_HWP_REQUEST, IA32_HWP_STATUS) are supported if set.
2995    ///
2996    /// # Platforms
2997    /// ❌ AMD (reserved) ✅ Intel
2998    pub fn has_hwp(&self) -> bool {
2999        self.eax.contains(ThermalPowerFeaturesEax::HWP)
3000    }
3001
3002    /// HWP Notification. IA32_HWP_INTERRUPT MSR is supported if set.
3003    ///
3004    /// # Platforms
3005    /// ❌ AMD (reserved) ✅ Intel
3006    pub fn has_hwp_notification(&self) -> bool {
3007        self.eax.contains(ThermalPowerFeaturesEax::HWP_NOTIFICATION)
3008    }
3009
3010    /// HWP Activity Window. IA32_HWP_REQUEST[bits 41:32] is supported if set.
3011    ///
3012    /// # Platforms
3013    /// ❌ AMD (reserved) ✅ Intel
3014    pub fn has_hwp_activity_window(&self) -> bool {
3015        self.eax
3016            .contains(ThermalPowerFeaturesEax::HWP_ACTIVITY_WINDOW)
3017    }
3018
3019    /// HWP Energy Performance Preference. IA32_HWP_REQUEST[bits 31:24] is
3020    /// supported if set.
3021    ///
3022    /// # Platforms
3023    /// ❌ AMD (reserved) ✅ Intel
3024    pub fn has_hwp_energy_performance_preference(&self) -> bool {
3025        self.eax
3026            .contains(ThermalPowerFeaturesEax::HWP_ENERGY_PERFORMANCE_PREFERENCE)
3027    }
3028
3029    /// HWP Package Level Request. IA32_HWP_REQUEST_PKG MSR is supported if set.
3030    ///
3031    /// # Platforms
3032    /// ❌ AMD (reserved) ✅ Intel
3033    pub fn has_hwp_package_level_request(&self) -> bool {
3034        self.eax
3035            .contains(ThermalPowerFeaturesEax::HWP_PACKAGE_LEVEL_REQUEST)
3036    }
3037
3038    /// HDC. HDC base registers IA32_PKG_HDC_CTL, IA32_PM_CTL1,
3039    /// IA32_THREAD_STALL MSRs are supported if set.
3040    ///
3041    /// # Platforms
3042    /// ❌ AMD (reserved) ✅ Intel
3043    pub fn has_hdc(&self) -> bool {
3044        self.eax.contains(ThermalPowerFeaturesEax::HDC)
3045    }
3046
3047    /// Intel® Turbo Boost Max Technology 3.0 available.
3048    ///
3049    /// # Platforms
3050    /// ❌ AMD (reserved) ✅ Intel
3051    pub fn has_turbo_boost3(&self) -> bool {
3052        self.eax.contains(ThermalPowerFeaturesEax::TURBO_BOOST_3)
3053    }
3054
3055    /// HWP Capabilities. Highest Performance change is supported if set.
3056    ///
3057    /// # Platforms
3058    /// ❌ AMD (reserved) ✅ Intel
3059    pub fn has_hwp_capabilities(&self) -> bool {
3060        self.eax.contains(ThermalPowerFeaturesEax::HWP_CAPABILITIES)
3061    }
3062
3063    /// HWP PECI override is supported if set.
3064    ///
3065    /// # Platforms
3066    /// ❌ AMD (reserved) ✅ Intel
3067    pub fn has_hwp_peci_override(&self) -> bool {
3068        self.eax
3069            .contains(ThermalPowerFeaturesEax::HWP_PECI_OVERRIDE)
3070    }
3071
3072    /// Flexible HWP is supported if set.
3073    ///
3074    /// # Platforms
3075    /// ❌ AMD (reserved) ✅ Intel
3076    pub fn has_flexible_hwp(&self) -> bool {
3077        self.eax.contains(ThermalPowerFeaturesEax::FLEXIBLE_HWP)
3078    }
3079
3080    /// Fast access mode for the IA32_HWP_REQUEST MSR is supported if set.
3081    ///
3082    /// # Platforms
3083    /// ❌ AMD (reserved) ✅ Intel
3084    pub fn has_hwp_fast_access_mode(&self) -> bool {
3085        self.eax
3086            .contains(ThermalPowerFeaturesEax::HWP_REQUEST_MSR_FAST_ACCESS)
3087    }
3088
3089    /// Ignoring Idle Logical Processor HWP request is supported if set.
3090    ///
3091    /// # Platforms
3092    /// ❌ AMD (reserved) ✅ Intel
3093    pub fn has_ignore_idle_processor_hwp_request(&self) -> bool {
3094        self.eax
3095            .contains(ThermalPowerFeaturesEax::IGNORE_IDLE_PROCESSOR_HWP_REQUEST)
3096    }
3097
3098    /// Hardware Coordination Feedback Capability
3099    ///
3100    /// Presence of IA32_MPERF and IA32_APERF.
3101    ///
3102    /// The capability to provide a measure of delivered processor performance
3103    /// (since last reset of the counters), as a percentage of expected
3104    /// processor performance at frequency specified in CPUID Brand String Bits
3105    /// 02 - 01
3106    ///
3107    /// # Platforms
3108    /// ✅ AMD ✅ Intel
3109    pub fn has_hw_coord_feedback(&self) -> bool {
3110        self.ecx
3111            .contains(ThermalPowerFeaturesEcx::HW_COORD_FEEDBACK)
3112    }
3113
3114    /// The processor supports performance-energy bias preference if
3115    /// CPUID.06H:ECX.SETBH[bit 3] is set and it also implies the presence of a
3116    /// new architectural MSR called IA32_ENERGY_PERF_BIAS (1B0H)
3117    ///
3118    /// # Platforms
3119    /// ❌ AMD (reserved) ✅ Intel
3120    pub fn has_energy_bias_pref(&self) -> bool {
3121        self.ecx.contains(ThermalPowerFeaturesEcx::ENERGY_BIAS_PREF)
3122    }
3123}
3124
3125impl Debug for ThermalPowerInfo {
3126    fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
3127        f.debug_struct("ThermalPowerInfo")
3128            .field("dts_irq_threshold", &self.dts_irq_threshold())
3129            .field("has_dts", &self.has_dts())
3130            .field("has_arat", &self.has_arat())
3131            .field("has_pln", &self.has_pln())
3132            .field("has_ecmd", &self.has_ecmd())
3133            .field("has_ptm", &self.has_ptm())
3134            .field("has_hwp", &self.has_hwp())
3135            .field("has_hwp_notification", &self.has_hwp_notification())
3136            .field("has_hwp_activity_window", &self.has_hwp_activity_window())
3137            .field(
3138                "has_hwp_energy_performance_preference",
3139                &self.has_hwp_energy_performance_preference(),
3140            )
3141            .field(
3142                "has_hwp_package_level_request",
3143                &self.has_hwp_package_level_request(),
3144            )
3145            .field("has_hdc", &self.has_hdc())
3146            .field("has_turbo_boost3", &self.has_turbo_boost3())
3147            .field("has_hwp_capabilities", &self.has_hwp_capabilities())
3148            .field("has_hwp_peci_override", &self.has_hwp_peci_override())
3149            .field("has_flexible_hwp", &self.has_flexible_hwp())
3150            .field("has_hwp_fast_access_mode", &self.has_hwp_fast_access_mode())
3151            .field(
3152                "has_ignore_idle_processor_hwp_request",
3153                &self.has_ignore_idle_processor_hwp_request(),
3154            )
3155            .field("has_hw_coord_feedback", &self.has_hw_coord_feedback())
3156            .field("has_energy_bias_pref", &self.has_energy_bias_pref())
3157            .finish()
3158    }
3159}
3160
3161bitflags! {
3162    struct ThermalPowerFeaturesEax: u32 {
3163        /// Digital temperature sensor is supported if set. (Bit 00)
3164        const DTS = 1 << 0;
3165        /// Intel Turbo Boost Technology Available (see description of IA32_MISC_ENABLE[38]). (Bit 01)
3166        const TURBO_BOOST = 1 << 1;
3167        /// ARAT. APIC-Timer-always-running feature is supported if set. (Bit 02)
3168        const ARAT = 1 << 2;
3169        /// Bit 3: Reserved.
3170        const RESERVED_3 = 1 << 3;
3171        /// PLN. Power limit notification controls are supported if set. (Bit 04)
3172        const PLN = 1 << 4;
3173        /// ECMD. Clock modulation duty cycle extension is supported if set. (Bit 05)
3174        const ECMD = 1 << 5;
3175        /// PTM. Package thermal management is supported if set. (Bit 06)
3176        const PTM = 1 << 6;
3177        /// Bit 07: HWP. HWP base registers (IA32_PM_ENABLE[bit 0], IA32_HWP_CAPABILITIES, IA32_HWP_REQUEST, IA32_HWP_STATUS) are supported if set.
3178        const HWP = 1 << 7;
3179        /// Bit 08: HWP_Notification. IA32_HWP_INTERRUPT MSR is supported if set.
3180        const HWP_NOTIFICATION = 1 << 8;
3181        /// Bit 09: HWP_Activity_Window. IA32_HWP_REQUEST[bits 41:32] is supported if set.
3182        const HWP_ACTIVITY_WINDOW = 1 << 9;
3183        /// Bit 10: HWP_Energy_Performance_Preference. IA32_HWP_REQUEST[bits 31:24] is supported if set.
3184        const HWP_ENERGY_PERFORMANCE_PREFERENCE = 1 << 10;
3185        /// Bit 11: HWP_Package_Level_Request. IA32_HWP_REQUEST_PKG MSR is supported if set.
3186        const HWP_PACKAGE_LEVEL_REQUEST = 1 << 11;
3187        /// Bit 12: Reserved.
3188        const RESERVED_12 = 1 << 12;
3189        /// Bit 13: HDC. HDC base registers IA32_PKG_HDC_CTL, IA32_PM_CTL1, IA32_THREAD_STALL MSRs are supported if set.
3190        const HDC = 1 << 13;
3191        /// Bit 14: Intel® Turbo Boost Max Technology 3.0 available.
3192        const TURBO_BOOST_3 = 1 << 14;
3193        /// Bit 15: HWP Capabilities. Highest Performance change is supported if set.
3194        const HWP_CAPABILITIES = 1 << 15;
3195        /// Bit 16: HWP PECI override is supported if set.
3196        const HWP_PECI_OVERRIDE = 1 << 16;
3197        /// Bit 17: Flexible HWP is supported if set.
3198        const FLEXIBLE_HWP = 1 << 17;
3199        /// Bit 18: Fast access mode for the IA32_HWP_REQUEST MSR is supported if set.
3200        const HWP_REQUEST_MSR_FAST_ACCESS = 1 << 18;
3201        /// Bit 19: Reserved.
3202        const RESERVED_19 = 1 << 19;
3203        /// Bit 20: Ignoring Idle Logical Processor HWP request is supported if set.
3204        const IGNORE_IDLE_PROCESSOR_HWP_REQUEST = 1 << 20;
3205        // Bits 31 - 21: Reserved
3206    }
3207}
3208
3209bitflags! {
3210    struct ThermalPowerFeaturesEcx: u32 {
3211        const HW_COORD_FEEDBACK = 1 << 0;
3212
3213        /// 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)
3214        const ENERGY_BIAS_PREF = 1 << 3;
3215    }
3216}
3217
3218/// Structured Extended Feature Identifiers (LEAF=0x07).
3219///
3220/// # Platforms
3221/// 🟡 AMD ✅ Intel
3222pub struct ExtendedFeatures {
3223    _eax: u32,
3224    ebx: ExtendedFeaturesEbx,
3225    ecx: ExtendedFeaturesEcx,
3226    edx: ExtendedFeaturesEdx,
3227    eax1: ExtendedFeaturesEax1,
3228    _ebx1: u32,
3229    _ecx1: u32,
3230    edx1: ExtendedFeaturesEdx1,
3231}
3232
3233impl ExtendedFeatures {
3234    /// FSGSBASE. Supports RDFSBASE/RDGSBASE/WRFSBASE/WRGSBASE if 1.
3235    ///
3236    /// # Platforms
3237    /// ✅ AMD ✅ Intel
3238    #[inline]
3239    pub const fn has_fsgsbase(&self) -> bool {
3240        self.ebx.contains(ExtendedFeaturesEbx::FSGSBASE)
3241    }
3242
3243    /// IA32_TSC_ADJUST MSR is supported if 1.
3244    ///
3245    /// # Platforms
3246    /// ❌ AMD (reserved) ✅ Intel
3247    #[inline]
3248    pub const fn has_tsc_adjust_msr(&self) -> bool {
3249        self.ebx.contains(ExtendedFeaturesEbx::ADJUST_MSR)
3250    }
3251
3252    /// BMI1
3253    ///
3254    /// # Platforms
3255    /// ✅ AMD ✅ Intel
3256    #[inline]
3257    pub const fn has_bmi1(&self) -> bool {
3258        self.ebx.contains(ExtendedFeaturesEbx::BMI1)
3259    }
3260
3261    /// HLE
3262    ///
3263    /// # Platforms
3264    /// ❌ AMD (reserved) ✅ Intel
3265    #[inline]
3266    pub const fn has_hle(&self) -> bool {
3267        self.ebx.contains(ExtendedFeaturesEbx::HLE)
3268    }
3269
3270    /// AVX2
3271    ///
3272    /// # Platforms
3273    /// ✅ AMD ✅ Intel
3274    #[inline]
3275    pub const fn has_avx2(&self) -> bool {
3276        self.ebx.contains(ExtendedFeaturesEbx::AVX2)
3277    }
3278
3279    /// FDP_EXCPTN_ONLY. x87 FPU Data Pointer updated only on x87 exceptions if
3280    /// 1.
3281    ///
3282    /// # Platforms
3283    /// ❌ AMD (reserved) ✅ Intel
3284    #[inline]
3285    pub const fn has_fdp(&self) -> bool {
3286        self.ebx.contains(ExtendedFeaturesEbx::FDP)
3287    }
3288
3289    /// SMEP. Supports Supervisor-Mode Execution Prevention if 1.
3290    ///
3291    /// # Platforms
3292    /// ✅ AMD ✅ Intel
3293    #[inline]
3294    pub const fn has_smep(&self) -> bool {
3295        self.ebx.contains(ExtendedFeaturesEbx::SMEP)
3296    }
3297
3298    /// BMI2
3299    ///
3300    /// # Platforms
3301    /// ✅ AMD ✅ Intel
3302    #[inline]
3303    pub const fn has_bmi2(&self) -> bool {
3304        self.ebx.contains(ExtendedFeaturesEbx::BMI2)
3305    }
3306
3307    /// Supports Enhanced REP MOVSB/STOSB if 1.
3308    ///
3309    /// # Platforms
3310    /// ❌ AMD (reserved) ✅ Intel
3311    #[inline]
3312    pub const fn has_rep_movsb_stosb(&self) -> bool {
3313        self.ebx.contains(ExtendedFeaturesEbx::REP_MOVSB_STOSB)
3314    }
3315
3316    /// INVPCID. If 1, supports INVPCID instruction for system software that
3317    /// manages process-context identifiers.
3318    ///
3319    /// # Platforms
3320    /// ❌ AMD (reserved) ✅ Intel
3321    #[inline]
3322    pub const fn has_invpcid(&self) -> bool {
3323        self.ebx.contains(ExtendedFeaturesEbx::INVPCID)
3324    }
3325
3326    /// RTM
3327    ///
3328    /// # Platforms
3329    /// ❌ AMD (reserved) ✅ Intel
3330    #[inline]
3331    pub const fn has_rtm(&self) -> bool {
3332        self.ebx.contains(ExtendedFeaturesEbx::RTM)
3333    }
3334
3335    /// Supports Intel Resource Director Technology (RDT) Monitoring capability.
3336    ///
3337    /// # Platforms
3338    /// ❌ AMD (reserved) ✅ Intel
3339    #[inline]
3340    pub const fn has_rdtm(&self) -> bool {
3341        self.ebx.contains(ExtendedFeaturesEbx::RDTM)
3342    }
3343
3344    /// Deprecates FPU CS and FPU DS values if 1.
3345    ///
3346    /// # Platforms
3347    /// ❌ AMD (reserved) ✅ Intel
3348    #[inline]
3349    pub const fn has_fpu_cs_ds_deprecated(&self) -> bool {
3350        self.ebx.contains(ExtendedFeaturesEbx::DEPRECATE_FPU_CS_DS)
3351    }
3352
3353    /// MPX. Supports Intel Memory Protection Extensions if 1.
3354    ///
3355    /// # Platforms
3356    /// ❌ AMD (reserved) ✅ Intel
3357    #[inline]
3358    pub const fn has_mpx(&self) -> bool {
3359        self.ebx.contains(ExtendedFeaturesEbx::MPX)
3360    }
3361
3362    /// Supports Intel Resource Director Technology (RDT) Allocation capability.
3363    ///
3364    /// # Platforms
3365    /// ❌ AMD (reserved) ✅ Intel
3366    #[inline]
3367    pub const fn has_rdta(&self) -> bool {
3368        self.ebx.contains(ExtendedFeaturesEbx::RDTA)
3369    }
3370
3371    /// Supports RDSEED.
3372    ///
3373    /// # Platforms
3374    /// ✅ AMD ✅ Intel
3375    #[inline]
3376    pub const fn has_rdseed(&self) -> bool {
3377        self.ebx.contains(ExtendedFeaturesEbx::RDSEED)
3378    }
3379
3380    /// Supports ADX.
3381    ///
3382    /// # Platforms
3383    /// ✅ AMD ✅ Intel
3384    #[inline]
3385    pub const fn has_adx(&self) -> bool {
3386        self.ebx.contains(ExtendedFeaturesEbx::ADX)
3387    }
3388
3389    /// SMAP. Supports Supervisor-Mode Access Prevention (and the CLAC/STAC
3390    /// instructions) if 1.
3391    ///
3392    /// # Platforms
3393    /// ✅ AMD ✅ Intel
3394    #[inline]
3395    pub const fn has_smap(&self) -> bool {
3396        self.ebx.contains(ExtendedFeaturesEbx::SMAP)
3397    }
3398
3399    /// Supports CLFLUSHOPT.
3400    ///
3401    /// # Platforms
3402    /// ✅ AMD ✅ Intel
3403    #[inline]
3404    pub const fn has_clflushopt(&self) -> bool {
3405        self.ebx.contains(ExtendedFeaturesEbx::CLFLUSHOPT)
3406    }
3407
3408    /// Supports Intel Processor Trace.
3409    ///
3410    /// # Platforms
3411    /// ❌ AMD (reserved) ✅ Intel
3412    #[inline]
3413    pub const fn has_processor_trace(&self) -> bool {
3414        self.ebx.contains(ExtendedFeaturesEbx::PROCESSOR_TRACE)
3415    }
3416
3417    /// Supports SHA Instructions.
3418    ///
3419    /// # Platforms
3420    /// ❌ AMD (reserved) ✅ Intel
3421    #[inline]
3422    pub const fn has_sha(&self) -> bool {
3423        self.ebx.contains(ExtendedFeaturesEbx::SHA)
3424    }
3425
3426    /// Supports Intel® Software Guard Extensions (Intel® SGX Extensions).
3427    ///
3428    /// # Platforms
3429    /// ❌ AMD (reserved) ✅ Intel
3430    #[inline]
3431    pub const fn has_sgx(&self) -> bool {
3432        self.ebx.contains(ExtendedFeaturesEbx::SGX)
3433    }
3434
3435    /// Supports AVX512F.
3436    ///
3437    /// # Platforms
3438    /// ✅ AMD ✅ Intel
3439    #[inline]
3440    pub const fn has_avx512f(&self) -> bool {
3441        self.ebx.contains(ExtendedFeaturesEbx::AVX512F)
3442    }
3443
3444    /// Supports AVX512DQ.
3445    ///
3446    /// # Platforms
3447    /// ✅ AMD ✅ Intel
3448    #[inline]
3449    pub const fn has_avx512dq(&self) -> bool {
3450        self.ebx.contains(ExtendedFeaturesEbx::AVX512DQ)
3451    }
3452
3453    /// AVX512_IFMA
3454    ///
3455    /// # Platforms
3456    /// ✅ AMD ✅ Intel
3457    #[inline]
3458    pub const fn has_avx512_ifma(&self) -> bool {
3459        self.ebx.contains(ExtendedFeaturesEbx::AVX512_IFMA)
3460    }
3461
3462    /// AVX512PF
3463    ///
3464    /// # Platforms
3465    /// ✅ AMD ✅ Intel
3466    #[inline]
3467    pub const fn has_avx512pf(&self) -> bool {
3468        self.ebx.contains(ExtendedFeaturesEbx::AVX512PF)
3469    }
3470
3471    /// AVX512ER
3472    ///
3473    /// # Platforms
3474    /// ✅ AMD ✅ Intel
3475    #[inline]
3476    pub const fn has_avx512er(&self) -> bool {
3477        self.ebx.contains(ExtendedFeaturesEbx::AVX512ER)
3478    }
3479
3480    /// AVX512CD
3481    ///
3482    /// # Platforms
3483    /// ✅ AMD ✅ Intel
3484    #[inline]
3485    pub const fn has_avx512cd(&self) -> bool {
3486        self.ebx.contains(ExtendedFeaturesEbx::AVX512CD)
3487    }
3488
3489    /// AVX512BW
3490    ///
3491    /// # Platforms
3492    /// ✅ AMD ✅ Intel
3493    #[inline]
3494    pub const fn has_avx512bw(&self) -> bool {
3495        self.ebx.contains(ExtendedFeaturesEbx::AVX512BW)
3496    }
3497
3498    /// AVX512VL
3499    ///
3500    /// # Platforms
3501    /// ✅ AMD ✅ Intel
3502    #[inline]
3503    pub const fn has_avx512vl(&self) -> bool {
3504        self.ebx.contains(ExtendedFeaturesEbx::AVX512VL)
3505    }
3506
3507    /// CLWB
3508    ///
3509    /// # Platforms
3510    /// ✅ AMD ✅ Intel
3511    #[inline]
3512    pub const fn has_clwb(&self) -> bool {
3513        self.ebx.contains(ExtendedFeaturesEbx::CLWB)
3514    }
3515
3516    /// Has PREFETCHWT1 (Intel® Xeon Phi™ only).
3517    ///
3518    /// # Platforms
3519    /// ❌ AMD (reserved) ✅ Intel
3520    #[inline]
3521    pub const fn has_prefetchwt1(&self) -> bool {
3522        self.ecx.contains(ExtendedFeaturesEcx::PREFETCHWT1)
3523    }
3524
3525    /// AVX512VBMI
3526    ///
3527    /// ✅ AMD ✅ Intel
3528    #[inline]
3529    pub const fn has_avx512vbmi(&self) -> bool {
3530        self.ecx.contains(ExtendedFeaturesEcx::AVX512VBMI)
3531    }
3532
3533    /// Supports user-mode instruction prevention if 1.
3534    ///
3535    /// # Platforms
3536    /// ❌ AMD (reserved) ✅ Intel
3537    #[inline]
3538    pub const fn has_umip(&self) -> bool {
3539        self.ecx.contains(ExtendedFeaturesEcx::UMIP)
3540    }
3541
3542    /// Supports protection keys for user-mode pages.
3543    ///
3544    /// # Platforms
3545    /// ❌ AMD (reserved) ✅ Intel
3546    #[inline]
3547    pub const fn has_pku(&self) -> bool {
3548        self.ecx.contains(ExtendedFeaturesEcx::PKU)
3549    }
3550
3551    /// OS has set CR4.PKE to enable protection keys (and the RDPKRU/WRPKRU
3552    /// instructions.
3553    ///
3554    /// # Platforms
3555    /// ❌ AMD (reserved) ✅ Intel
3556    #[inline]
3557    pub const fn has_ospke(&self) -> bool {
3558        self.ecx.contains(ExtendedFeaturesEcx::OSPKE)
3559    }
3560
3561    /// WAITPKG
3562    ///
3563    /// ❓ AMD ✅ Intel
3564    #[inline]
3565    pub const fn has_waitpkg(&self) -> bool {
3566        self.ecx.contains(ExtendedFeaturesEcx::WAITPKG)
3567    }
3568
3569    /// AVX512VBMI2
3570    ///
3571    /// ✅ AMD ✅ Intel
3572    #[deprecated(since = "11.4.0", note = "Please use `has_avx512vbmi2` instead")]
3573    #[inline]
3574    pub const fn has_av512vbmi2(&self) -> bool {
3575        self.ecx.contains(ExtendedFeaturesEcx::AVX512VBMI2)
3576    }
3577
3578    /// AVX512VBMI2
3579    ///
3580    /// ✅ AMD ✅ Intel
3581    #[inline]
3582    pub const fn has_avx512vbmi2(&self) -> bool {
3583        self.ecx.contains(ExtendedFeaturesEcx::AVX512VBMI2)
3584    }
3585
3586    /// Supports CET shadow stack features. Processors that set this bit define bits 0..2 of the
3587    /// IA32_U_CET and IA32_S_CET MSRs. Enumerates support for the following MSRs:
3588    /// IA32_INTERRUPT_SPP_TABLE_ADDR, IA32_PL3_SSP, IA32_PL2_SSP, IA32_PL1_SSP, and IA32_PL0_SSP.
3589    ///
3590    /// ❓ AMD ✅ Intel
3591    #[inline]
3592    pub const fn has_cet_ss(&self) -> bool {
3593        self.ecx.contains(ExtendedFeaturesEcx::CETSS)
3594    }
3595
3596    /// GFNI
3597    ///
3598    /// ❓ AMD ✅ Intel
3599    #[inline]
3600    pub const fn has_gfni(&self) -> bool {
3601        self.ecx.contains(ExtendedFeaturesEcx::GFNI)
3602    }
3603
3604    /// VAES
3605    ///
3606    /// ❓ AMD ✅ Intel
3607    #[inline]
3608    pub const fn has_vaes(&self) -> bool {
3609        self.ecx.contains(ExtendedFeaturesEcx::VAES)
3610    }
3611
3612    /// VPCLMULQDQ
3613    ///
3614    /// ❓ AMD ✅ Intel
3615    #[inline]
3616    pub const fn has_vpclmulqdq(&self) -> bool {
3617        self.ecx.contains(ExtendedFeaturesEcx::VPCLMULQDQ)
3618    }
3619
3620    /// AVX512VNNI
3621    ///
3622    /// # Platforms
3623    /// ✅ AMD ✅ Intel
3624    #[inline]
3625    pub const fn has_avx512vnni(&self) -> bool {
3626        self.ecx.contains(ExtendedFeaturesEcx::AVX512VNNI)
3627    }
3628
3629    /// AVX512BITALG
3630    ///
3631    /// ✅ AMD ✅ Intel
3632    #[inline]
3633    pub const fn has_avx512bitalg(&self) -> bool {
3634        self.ecx.contains(ExtendedFeaturesEcx::AVX512BITALG)
3635    }
3636
3637    /// Indicates the following MSRs are supported: IA32_TME_CAPABILITY, IA32_TME_ACTIVATE,
3638    /// IA32_TME_EXCLUDE_MASK, and IA32_TME_EXCLUDE_BASE.
3639    ///
3640    /// ❓ AMD ✅ Intel
3641    #[inline]
3642    pub const fn has_tme_en(&self) -> bool {
3643        self.ecx.contains(ExtendedFeaturesEcx::TMEEN)
3644    }
3645
3646    /// AVX512VPOPCNTDQ
3647    ///
3648    /// ✅ AMD ✅ Intel
3649    #[inline]
3650    pub const fn has_avx512vpopcntdq(&self) -> bool {
3651        self.ecx.contains(ExtendedFeaturesEcx::AVX512VPOPCNTDQ)
3652    }
3653
3654    /// Supports 57-bit linear addresses and five-level paging if 1.
3655    ///
3656    /// # Platforms
3657    /// ❓ AMD ✅ Intel
3658    #[inline]
3659    pub const fn has_la57(&self) -> bool {
3660        self.ecx.contains(ExtendedFeaturesEcx::LA57)
3661    }
3662
3663    /// RDPID and IA32_TSC_AUX are available.
3664    ///
3665    /// # Bug
3666    /// The Intel manual lists RDPID as bit 22 in the ECX register, but AMD
3667    /// lists it as bit 22 in the ebx register. We assumed that the AMD manual
3668    /// was wrong and query ecx, let's see what happens.
3669    ///
3670    /// # Platforms
3671    /// ✅ AMD ✅ Intel
3672    #[inline]
3673    pub const fn has_rdpid(&self) -> bool {
3674        self.ecx.contains(ExtendedFeaturesEcx::RDPID)
3675    }
3676
3677    /// Supports SGX Launch Configuration.
3678    ///
3679    /// # Platforms
3680    /// ❌ AMD (reserved) ✅ Intel
3681    #[inline]
3682    pub const fn has_sgx_lc(&self) -> bool {
3683        self.ecx.contains(ExtendedFeaturesEcx::SGX_LC)
3684    }
3685
3686    /// The value of MAWAU used by the BNDLDX and BNDSTX instructions in 64-bit mode.
3687    ///
3688    /// # Platforms
3689    /// ❌ AMD (reserved) ✅ Intel
3690    #[inline]
3691    pub fn mawau_value(&self) -> u8 {
3692        get_bits(self.ecx.bits(), 17, 21) as u8
3693    }
3694
3695    /// Supports AVX512_4VNNIW.
3696    ///
3697    /// # Platforms
3698    /// ❌ AMD (reserved) ✅ Intel
3699    #[inline]
3700    pub const fn has_avx512_4vnniw(&self) -> bool {
3701        self.edx.contains(ExtendedFeaturesEdx::AVX512_4VNNIW)
3702    }
3703
3704    /// Supports AVX512_4FMAPS.
3705    ///
3706    /// # Platforms
3707    /// ❌ AMD (reserved) ✅ Intel
3708    #[inline]
3709    pub const fn has_avx512_4fmaps(&self) -> bool {
3710        self.edx.contains(ExtendedFeaturesEdx::AVX512_4FMAPS)
3711    }
3712
3713    /// Supports AVX512_VP2INTERSECT.
3714    ///
3715    /// # Platforms
3716    /// ❌ AMD (reserved) ✅ Intel
3717    #[inline]
3718    pub const fn has_avx512_vp2intersect(&self) -> bool {
3719        self.edx.contains(ExtendedFeaturesEdx::AVX512_VP2INTERSECT)
3720    }
3721
3722    /// Supports AMX_BF16.
3723    ///
3724    /// # Platforms
3725    /// ❌ AMD (reserved) ✅ Intel
3726    #[inline]
3727    pub const fn has_amx_bf16(&self) -> bool {
3728        self.edx.contains(ExtendedFeaturesEdx::AMX_BF16)
3729    }
3730
3731    /// Supports AVX512_FP16.
3732    ///
3733    /// # Platforms
3734    /// ❌ AMD (reserved) ✅ Intel
3735    #[inline]
3736    pub const fn has_avx512_fp16(&self) -> bool {
3737        self.edx.contains(ExtendedFeaturesEdx::AVX512_FP16)
3738    }
3739
3740    /// Supports AMX_TILE.
3741    ///
3742    /// # Platforms
3743    /// ❌ AMD (reserved) ✅ Intel
3744    #[inline]
3745    pub const fn has_amx_tile(&self) -> bool {
3746        self.edx.contains(ExtendedFeaturesEdx::AMX_TILE)
3747    }
3748
3749    /// Supports AMX_INT8.
3750    ///
3751    /// # Platforms
3752    /// ❌ AMD (reserved) ✅ Intel
3753    #[inline]
3754    pub const fn has_amx_int8(&self) -> bool {
3755        self.edx.contains(ExtendedFeaturesEdx::AMX_INT8)
3756    }
3757
3758    /// Supports AVX_VNNI.
3759    ///
3760    /// # Platforms
3761    /// ❌ AMD (reserved) ✅ Intel
3762    #[inline]
3763    pub const fn has_avx_vnni(&self) -> bool {
3764        self.eax1.contains(ExtendedFeaturesEax1::AVX_VNNI)
3765    }
3766
3767    /// Supports AVX512_BF16.
3768    ///
3769    /// # Platforms
3770    /// ❌ AMD (reserved) ✅ Intel
3771    #[inline]
3772    pub const fn has_avx512_bf16(&self) -> bool {
3773        self.eax1.contains(ExtendedFeaturesEax1::AVX512_BF16)
3774    }
3775
3776    /// Supports Fast zero-length REP MOVSB
3777    ///
3778    /// # Platforms
3779    /// ❌ AMD (reserved) ✅ Intel
3780    #[inline]
3781    pub const fn has_fzrm(&self) -> bool {
3782        self.eax1.contains(ExtendedFeaturesEax1::FZRM)
3783    }
3784
3785    /// Supports Fast Short REP STOSB
3786    ///
3787    /// # Platforms
3788    /// ❌ AMD (reserved) ✅ Intel
3789    #[inline]
3790    pub const fn has_fsrs(&self) -> bool {
3791        self.eax1.contains(ExtendedFeaturesEax1::FSRS)
3792    }
3793
3794    /// Supports Fast Short REP CMPSB, REP SCASB
3795    ///
3796    /// # Platforms
3797    /// ❌ AMD (reserved) ✅ Intel
3798    #[inline]
3799    pub const fn has_fsrcrs(&self) -> bool {
3800        self.eax1.contains(ExtendedFeaturesEax1::FSRCRS)
3801    }
3802
3803    /// Supports HRESET
3804    ///
3805    /// # Platforms
3806    /// ❌ AMD (reserved) ✅ Intel
3807    #[inline]
3808    pub const fn has_hreset(&self) -> bool {
3809        self.eax1.contains(ExtendedFeaturesEax1::HRESET)
3810    }
3811
3812    /// Supports AVX-IFMA Instructions.
3813    ///
3814    /// # Platforms
3815    /// ❌ AMD (reserved) ✅ Intel
3816    #[inline]
3817    pub const fn has_avx_ifma(&self) -> bool {
3818        self.eax1.contains(ExtendedFeaturesEax1::AVX_IFMA)
3819    }
3820
3821    /// Supports Linear Address Masking.
3822    ///
3823    /// # Platforms
3824    /// ❌ AMD (reserved) ✅ Intel
3825    #[inline]
3826    pub const fn has_lam(&self) -> bool {
3827        self.eax1.contains(ExtendedFeaturesEax1::LAM)
3828    }
3829
3830    /// Supports RDMSRLIST and WRMSRLIST Instructions and the IA32_BARRIER MSR.
3831    ///
3832    /// # Platforms
3833    /// ❌ AMD (reserved) ✅ Intel
3834    #[inline]
3835    pub const fn has_msrlist(&self) -> bool {
3836        self.eax1.contains(ExtendedFeaturesEax1::MSRLIST)
3837    }
3838
3839    /// Supports INVD execution prevention after BIOS Done.
3840    ///
3841    /// # Platforms
3842    /// ❌ AMD (reserved) ✅ Intel
3843    #[inline]
3844    pub const fn has_invd_disable_post_bios_done(&self) -> bool {
3845        self.eax1
3846            .contains(ExtendedFeaturesEax1::INVD_DISABLE_POST_BIOS_DONE)
3847    }
3848
3849    /// Supports AVX_VNNI_INT8
3850    ///
3851    /// # Platforms
3852    /// ❌ AMD (reserved) ✅ Intel
3853    #[inline]
3854    pub const fn has_avx_vnni_int8(&self) -> bool {
3855        self.edx1.contains(ExtendedFeaturesEdx1::AVX_VNNI_INT8)
3856    }
3857
3858    /// Supports AVX_NE_CONVERT
3859    ///
3860    /// # Platforms
3861    /// ❌ AMD (reserved) ✅ Intel
3862    #[inline]
3863    pub const fn has_avx_ne_convert(&self) -> bool {
3864        self.edx1.contains(ExtendedFeaturesEdx1::AVX_NE_CONVERT)
3865    }
3866
3867    /// Supports AVX_VNNI_INT16
3868    ///
3869    /// # Platforms
3870    /// ❌ AMD (reserved) ✅ Intel
3871    #[inline]
3872    pub const fn has_avx_vnni_int16(&self) -> bool {
3873        self.edx1.contains(ExtendedFeaturesEdx1::AVX_VNNI_INT16)
3874    }
3875
3876    /// Supports PREFETCHI
3877    ///
3878    /// # Platforms
3879    /// ❌ AMD (reserved) ✅ Intel
3880    #[inline]
3881    pub const fn has_prefetchi(&self) -> bool {
3882        self.edx1.contains(ExtendedFeaturesEdx1::PREFETCHI)
3883    }
3884
3885    /// Supports UIRET_UIF
3886    ///
3887    /// # Platforms
3888    /// ❌ AMD (reserved) ✅ Intel
3889    #[inline]
3890    pub const fn has_uiret_uif(&self) -> bool {
3891        self.edx1.contains(ExtendedFeaturesEdx1::UIRET_UIF)
3892    }
3893
3894    /// Supports CET_SSS
3895    ///
3896    /// # Platforms
3897    /// ❌ AMD (reserved) ✅ Intel
3898    #[inline]
3899    pub const fn has_cet_sss(&self) -> bool {
3900        self.edx1.contains(ExtendedFeaturesEdx1::CET_SSS)
3901    }
3902
3903    /// Supports AVX10
3904    ///
3905    /// # Platforms
3906    /// ❌ AMD (reserved) ✅ Intel
3907    #[inline]
3908    pub const fn has_avx10(&self) -> bool {
3909        self.edx1.contains(ExtendedFeaturesEdx1::AVX10)
3910    }
3911}
3912
3913impl Debug for ExtendedFeatures {
3914    fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
3915        f.debug_struct("ExtendedFeatures")
3916            .field("ebx", &self.ebx)
3917            .field("ecx", &self.ecx)
3918            .field("mawau_value", &self.mawau_value())
3919            .finish()
3920    }
3921}
3922
3923bitflags! {
3924    #[repr(transparent)]
3925    #[derive(Debug, Clone, Copy, PartialEq, Eq)]
3926    struct ExtendedFeaturesEbx: u32 {
3927        /// FSGSBASE. Supports RDFSBASE/RDGSBASE/WRFSBASE/WRGSBASE if 1. (Bit 00)
3928        const FSGSBASE = 1 << 0;
3929        /// IA32_TSC_ADJUST MSR is supported if 1. (Bit 01)
3930        const ADJUST_MSR = 1 << 1;
3931        /// Bit 02: SGX. Supports Intel® Software Guard Extensions (Intel® SGX Extensions) if 1.
3932        const SGX = 1 << 2;
3933        /// BMI1 (Bit 03)
3934        const BMI1 = 1 << 3;
3935        /// HLE (Bit 04)
3936        const HLE = 1 << 4;
3937        /// AVX2 (Bit 05)
3938        const AVX2 = 1 << 5;
3939        /// FDP_EXCPTN_ONLY. x87 FPU Data Pointer updated only on x87 exceptions if 1.
3940        const FDP = 1 << 6;
3941        /// SMEP. Supports Supervisor-Mode Execution Prevention if 1. (Bit 07)
3942        const SMEP = 1 << 7;
3943        /// BMI2 (Bit 08)
3944        const BMI2 = 1 << 8;
3945        /// Supports Enhanced REP MOVSB/STOSB if 1. (Bit 09)
3946        const REP_MOVSB_STOSB = 1 << 9;
3947        /// INVPCID. If 1, supports INVPCID instruction for system software that manages process-context identifiers. (Bit 10)
3948        const INVPCID = 1 << 10;
3949        /// RTM (Bit 11)
3950        const RTM = 1 << 11;
3951        /// Supports Intel Resource Director Technology (RDT) Monitoring. (Bit 12)
3952        const RDTM = 1 << 12;
3953        /// Deprecates FPU CS and FPU DS values if 1. (Bit 13)
3954        const DEPRECATE_FPU_CS_DS = 1 << 13;
3955        /// Deprecates FPU CS and FPU DS values if 1. (Bit 14)
3956        const MPX = 1 << 14;
3957        /// Supports Intel Resource Director Technology (RDT) Allocation capability if 1.
3958        const RDTA = 1 << 15;
3959        /// Bit 16: AVX512F.
3960        const AVX512F = 1 << 16;
3961        /// Bit 17: AVX512DQ.
3962        const AVX512DQ = 1 << 17;
3963        /// Supports RDSEED.
3964        const RDSEED = 1 << 18;
3965        /// Supports ADX.
3966        const ADX = 1 << 19;
3967        /// SMAP. Supports Supervisor-Mode Access Prevention (and the CLAC/STAC instructions) if 1.
3968        const SMAP = 1 << 20;
3969        /// Bit 21: AVX512_IFMA.
3970        const AVX512_IFMA = 1 << 21;
3971        // Bit 22: Reserved.
3972        /// Bit 23: CLFLUSHOPT
3973        const CLFLUSHOPT = 1 << 23;
3974        /// Bit 24: CLWB.
3975        const CLWB = 1 << 24;
3976        /// Bit 25: Intel Processor Trace
3977        const PROCESSOR_TRACE = 1 << 25;
3978        /// Bit 26: AVX512PF. (Intel® Xeon Phi™ only.)
3979        const AVX512PF = 1 << 26;
3980        /// Bit 27: AVX512ER. (Intel® Xeon Phi™ only.)
3981        const AVX512ER = 1 << 27;
3982        /// Bit 28: AVX512CD.
3983        const AVX512CD = 1 << 28;
3984        /// Bit 29: Intel SHA Extensions
3985        const SHA = 1 << 29;
3986        /// Bit 30: AVX512BW.
3987        const AVX512BW = 1 << 30;
3988        /// Bit 31: AVX512VL.
3989        const AVX512VL = 1 << 31;
3990    }
3991}
3992
3993bitflags! {
3994    #[repr(transparent)]
3995    #[derive(Debug, Clone, Copy, PartialEq, Eq)]
3996    struct ExtendedFeaturesEcx: u32 {
3997        /// Bit 0: Prefetch WT1. (Intel® Xeon Phi™ only).
3998        const PREFETCHWT1 = 1 << 0;
3999        // Bit 01: AVX512_VBMI
4000        const AVX512VBMI = 1 << 1;
4001        /// Bit 02: UMIP. Supports user-mode instruction prevention if 1.
4002        const UMIP = 1 << 2;
4003        /// Bit 03: PKU. Supports protection keys for user-mode pages if 1.
4004        const PKU = 1 << 3;
4005        /// Bit 04: OSPKE. If 1, OS has set CR4.PKE to enable protection keys (and the RDPKRU/WRPKRU instruc-tions).
4006        const OSPKE = 1 << 4;
4007        /// Bit 5: WAITPKG
4008        const WAITPKG = 1 << 5;
4009        /// Bit 6: AV512_VBMI2
4010        const AVX512VBMI2 = 1 << 6;
4011        /// Bit 7: CET_SS. Supports CET shadow stack features if 1. Processors that set this bit define bits 0..2 of the
4012        /// IA32_U_CET and IA32_S_CET MSRs. Enumerates support for the following MSRs:
4013        /// IA32_INTERRUPT_SPP_TABLE_ADDR, IA32_PL3_SSP, IA32_PL2_SSP, IA32_PL1_SSP, and IA32_PL0_SSP.
4014        const CETSS = 1 << 7;
4015        /// Bit 8: GFNI
4016        const GFNI = 1 << 8;
4017        /// Bit 9: VAES
4018        const VAES = 1 << 9;
4019        /// Bit 10: VPCLMULQDQ
4020        const VPCLMULQDQ = 1 << 10;
4021        /// Bit 11: AVX512_VNNI
4022        const AVX512VNNI = 1 << 11;
4023        /// Bit 12: AVX512_BITALG
4024        const AVX512BITALG = 1 << 12;
4025        /// Bit 13: TME_EN. If 1, the following MSRs are supported: IA32_TME_CAPABILITY, IA32_TME_ACTIVATE,
4026        /// IA32_TME_EXCLUDE_MASK, and IA32_TME_EXCLUDE_BASE.
4027        const TMEEN = 1 << 13;
4028        /// Bit 14: AVX512_VPOPCNTDQ
4029        const AVX512VPOPCNTDQ = 1 << 14;
4030
4031        // Bit 15: Reserved.
4032
4033        /// Bit 16: Supports 57-bit linear addresses and five-level paging if 1.
4034        const LA57 = 1 << 16;
4035
4036        // Bits 21 - 17: The value of MAWAU used by the BNDLDX and BNDSTX instructions in 64-bit mode
4037
4038        /// Bit 22: RDPID. RDPID and IA32_TSC_AUX are available if 1.
4039        const RDPID = 1 << 22;
4040
4041        // Bits 29 - 23: Reserved.
4042
4043        /// Bit 30: SGX_LC. Supports SGX Launch Configuration if 1.
4044        const SGX_LC = 1 << 30;
4045    }
4046}
4047
4048bitflags! {
4049    #[repr(transparent)]
4050    #[derive(Debug, Clone, Copy, PartialEq, Eq)]
4051    struct ExtendedFeaturesEdx: u32 {
4052        /// Bit 02: AVX512_4VNNIW. (Intel® Xeon Phi™ only).
4053        const AVX512_4VNNIW = 1 << 2;
4054        /// Bit 03: AVX512_4FMAPS. (Intel® Xeon Phi™ only).
4055        const AVX512_4FMAPS = 1 << 3;
4056        /// Bit 08: AVX512_VP2INTERSECT.
4057        const AVX512_VP2INTERSECT = 1 << 8;
4058        /// Bit 22: AMX-BF16. If 1, the processor supports tile computational operations on bfloat16 numbers.
4059        const AMX_BF16 = 1 << 22;
4060        /// Bit 23: AVX512_FP16.
4061        const AVX512_FP16 = 1 << 23;
4062        /// Bit 24: AMX-TILE. If 1, the processor supports tile architecture
4063        const AMX_TILE = 1 << 24;
4064        /// Bit 25: AMX-INT8. If 1, the processor supports tile computational operations on 8-bit integers.
4065        const AMX_INT8 = 1 << 25;
4066    }
4067}
4068
4069bitflags! {
4070    #[repr(transparent)]
4071    #[derive(Debug, Clone, Copy, PartialEq, Eq)]
4072    struct ExtendedFeaturesEax1: u32 {
4073        // Some of the Unimplemented bits are reserved and maybe release in future CPUs, see Intel SDM for future features (Date of comment: 07.17.2024)
4074        /// Bit 04: AVX_VNNI. AVX (VEX-encoded) versions of the Vector Neural Network Instructions.
4075        const AVX_VNNI = 1 << 4;
4076        /// Bit 05: AVX512_BF16. Vector Neural Network Instructions supporting BFLOAT16 inputs and conversion instructions from IEEE single precision.
4077        const AVX512_BF16 = 1 << 5;
4078        /// Bit 10: If 1, supports fast zero-length REP MOVSB.
4079        const FZRM = 1 << 10;
4080        /// Bit 11: If 1, supports fast short REP STOSB.
4081        const FSRS = 1 << 11;
4082        /// Bit 12: If 1, supports fast short REP CMPSB, REP SCASB.
4083        const FSRCRS = 1 << 12;
4084        /// Bit 22: If 1, supports history reset via the HRESET instruction and the IA32_HRESET_ENABLE MSR. When set, indicates that the Processor History Reset Leaf (EAX = 20H) is valid.
4085        const HRESET = 1 << 22;
4086        /// Bit 23: If 1, supports the AVX-IFMA instructions.
4087        const AVX_IFMA = 1 << 23;
4088        /// Bit 26: If 1, supports Linear Address Masking.
4089        const LAM = 1 << 26;
4090        /// Bit 27: If 1, supports the RDMSRLIST and WRMSRLIST instructions and the IA32_BARRIER MSR.
4091        const MSRLIST = 1 << 27;
4092        /// Bit 30: If 1, supports INVD execution prevention after BIOS Done.
4093        const INVD_DISABLE_POST_BIOS_DONE = 1 << 30;
4094    }
4095}
4096
4097bitflags! {
4098    #[repr(transparent)]
4099    #[derive(Debug, Clone, Copy, PartialEq, Eq)]
4100    struct ExtendedFeaturesEdx1: u32 {
4101        // Some of the Unimplemented bits are reserved and maybe release in future CPUs, see Intel SDM for future features (Date of comment: 07.17.2024)
4102        /// Bit 4: If 1, supports the AVX-VNNI-INT8 instructions.
4103        const AVX_VNNI_INT8 = 1 << 4;
4104        /// Bit 5: If 1, supports the AVX-NE-CONVERT instructions.
4105        const AVX_NE_CONVERT = 1 << 5;
4106        /// Bit 10: If 1, supports the AVX-VNNI-INT16 instructions
4107        const AVX_VNNI_INT16 = 1 << 10;
4108        /// Bit 14: If 1, supports the PREFETCHIT0/1 instructions
4109        const PREFETCHI = 1 << 14;
4110        /// Bit 17: If 1, UIRET sets UIF to the value of bit 1 of the RFLAGS image loaded from the stack
4111        const UIRET_UIF = 1 << 17;
4112        /// Bit 18: CET_SSS. If 1, indicates that an operating system can enable supervisor shadow stacks as long as it ensures that a supervisor shadow stack cannot become prematurely busy due to page faults
4113        const CET_SSS = 1 << 18;
4114        /// Bit 19: If 1, supports the Intel® AVX10 instructions and indicates the presence of CPUID Leaf 24H,
4115        /// which enumerates version number and supported vector lengths
4116        const AVX10 = 1 << 19;
4117    }
4118}
4119
4120/// Direct cache access info (LEAF=0x09).
4121///
4122/// # Platforms
4123/// ❌ AMD (reserved) ✅ Intel
4124pub struct DirectCacheAccessInfo {
4125    eax: u32,
4126}
4127
4128impl DirectCacheAccessInfo {
4129    /// Value of bits \[31:0\] of IA32_PLATFORM_DCA_CAP MSR (address 1F8H)
4130    pub fn get_dca_cap_value(&self) -> u32 {
4131        self.eax
4132    }
4133}
4134
4135impl Debug for DirectCacheAccessInfo {
4136    fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
4137        f.debug_struct("DirectCacheAccessInfo")
4138            .field("dca_cap_value", &self.get_dca_cap_value())
4139            .finish()
4140    }
4141}
4142
4143/// Info about performance monitoring -- how many counters etc. (LEAF=0x0A)
4144///
4145/// # Platforms
4146/// ❌ AMD ✅ Intel
4147pub struct PerformanceMonitoringInfo {
4148    eax: u32,
4149    ebx: PerformanceMonitoringFeaturesEbx,
4150    _ecx: u32,
4151    edx: u32,
4152}
4153
4154impl PerformanceMonitoringInfo {
4155    /// Version ID of architectural performance monitoring. (Bits 07 - 00)
4156    pub fn version_id(&self) -> u8 {
4157        get_bits(self.eax, 0, 7) as u8
4158    }
4159
4160    /// Number of general-purpose performance monitoring counter per logical processor. (Bits 15- 08)
4161    pub fn number_of_counters(&self) -> u8 {
4162        get_bits(self.eax, 8, 15) as u8
4163    }
4164
4165    /// Bit width of general-purpose, performance monitoring counter. (Bits 23 - 16)
4166    pub fn counter_bit_width(&self) -> u8 {
4167        get_bits(self.eax, 16, 23) as u8
4168    }
4169
4170    /// Length of EBX bit vector to enumerate architectural performance monitoring events. (Bits 31 - 24)
4171    pub fn ebx_length(&self) -> u8 {
4172        get_bits(self.eax, 24, 31) as u8
4173    }
4174
4175    /// Number of fixed-function performance counters (if Version ID > 1). (Bits 04 - 00)
4176    pub fn fixed_function_counters(&self) -> u8 {
4177        get_bits(self.edx, 0, 4) as u8
4178    }
4179
4180    /// Bit width of fixed-function performance counters (if Version ID > 1). (Bits 12- 05)
4181    pub fn fixed_function_counters_bit_width(&self) -> u8 {
4182        get_bits(self.edx, 5, 12) as u8
4183    }
4184
4185    check_bit_fn!(
4186        doc = "AnyThread deprecation",
4187        has_any_thread_deprecation,
4188        edx,
4189        15
4190    );
4191
4192    check_flag!(
4193        doc = "Core cycle event not available if 1.",
4194        is_core_cyc_ev_unavailable,
4195        ebx,
4196        PerformanceMonitoringFeaturesEbx::CORE_CYC_EV_UNAVAILABLE
4197    );
4198
4199    check_flag!(
4200        doc = "Instruction retired event not available if 1.",
4201        is_inst_ret_ev_unavailable,
4202        ebx,
4203        PerformanceMonitoringFeaturesEbx::INST_RET_EV_UNAVAILABLE
4204    );
4205
4206    check_flag!(
4207        doc = "Reference cycles event not available if 1.",
4208        is_ref_cycle_ev_unavailable,
4209        ebx,
4210        PerformanceMonitoringFeaturesEbx::REF_CYC_EV_UNAVAILABLE
4211    );
4212
4213    check_flag!(
4214        doc = "Last-level cache reference event not available if 1.",
4215        is_cache_ref_ev_unavailable,
4216        ebx,
4217        PerformanceMonitoringFeaturesEbx::CACHE_REF_EV_UNAVAILABLE
4218    );
4219
4220    check_flag!(
4221        doc = "Last-level cache misses event not available if 1.",
4222        is_ll_cache_miss_ev_unavailable,
4223        ebx,
4224        PerformanceMonitoringFeaturesEbx::LL_CACHE_MISS_EV_UNAVAILABLE
4225    );
4226
4227    check_flag!(
4228        doc = "Branch instruction retired event not available if 1.",
4229        is_branch_inst_ret_ev_unavailable,
4230        ebx,
4231        PerformanceMonitoringFeaturesEbx::BRANCH_INST_RET_EV_UNAVAILABLE
4232    );
4233
4234    check_flag!(
4235        doc = "Branch mispredict retired event not available if 1.",
4236        is_branch_midpred_ev_unavailable,
4237        ebx,
4238        PerformanceMonitoringFeaturesEbx::BRANCH_MISPRED_EV_UNAVAILABLE
4239    );
4240}
4241
4242impl Debug for PerformanceMonitoringInfo {
4243    fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
4244        f.debug_struct("PerformanceMonitoringInfo")
4245            .field("version_id", &self.version_id())
4246            .field("number_of_counters", &self.number_of_counters())
4247            .field("counter_bit_width", &self.counter_bit_width())
4248            .field("ebx_length", &self.ebx_length())
4249            .field("fixed_function_counters", &self.fixed_function_counters())
4250            .field(
4251                "fixed_function_counters_bit_width",
4252                &self.fixed_function_counters_bit_width(),
4253            )
4254            .finish()
4255    }
4256}
4257
4258bitflags! {
4259    #[repr(transparent)]
4260    #[derive(Debug, Clone, Copy, PartialEq, Eq)]
4261    struct PerformanceMonitoringFeaturesEbx: u32 {
4262        /// Core cycle event not available if 1. (Bit 0)
4263        const CORE_CYC_EV_UNAVAILABLE = 1 << 0;
4264        /// Instruction retired event not available if 1. (Bit 01)
4265        const INST_RET_EV_UNAVAILABLE = 1 << 1;
4266        /// Reference cycles event not available if 1. (Bit 02)
4267        const REF_CYC_EV_UNAVAILABLE = 1 << 2;
4268        /// Last-level cache reference event not available if 1. (Bit 03)
4269        const CACHE_REF_EV_UNAVAILABLE = 1 << 3;
4270        /// Last-level cache misses event not available if 1. (Bit 04)
4271        const LL_CACHE_MISS_EV_UNAVAILABLE = 1 << 4;
4272        /// Branch instruction retired event not available if 1. (Bit 05)
4273        const BRANCH_INST_RET_EV_UNAVAILABLE = 1 << 5;
4274        /// Branch mispredict retired event not available if 1. (Bit 06)
4275        const BRANCH_MISPRED_EV_UNAVAILABLE = 1 << 6;
4276    }
4277}
4278
4279/// Information about topology (LEAF=0x0B).
4280///
4281/// Iterates over the system topology in order to retrieve more system
4282/// information at each level of the topology: how many cores and what kind of
4283/// cores
4284///
4285/// # Platforms
4286/// ✅ AMD ✅ Intel
4287#[derive(Clone)]
4288pub struct ExtendedTopologyIter<R: CpuIdReader> {
4289    read: R,
4290    level: u32,
4291    is_v2: bool,
4292}
4293
4294/// Gives information about the current level in the topology.
4295///
4296/// How many cores, what type etc.
4297#[derive(PartialEq, Eq)]
4298pub struct ExtendedTopologyLevel {
4299    eax: u32,
4300    ebx: u32,
4301    ecx: u32,
4302    edx: u32,
4303}
4304
4305impl fmt::Debug for ExtendedTopologyLevel {
4306    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
4307        f.debug_struct("ExtendedTopologyLevel")
4308            .field("processors", &self.processors())
4309            .field("number", &self.level_number())
4310            .field("type", &self.level_type())
4311            .field("x2apic_id", &self.x2apic_id())
4312            .field("next_apic_id", &self.shift_right_for_next_apic_id())
4313            .finish()
4314    }
4315}
4316
4317impl ExtendedTopologyLevel {
4318    /// Number of logical processors at this level type.
4319    /// The number reflects configuration as shipped.
4320    pub fn processors(&self) -> u16 {
4321        get_bits(self.ebx, 0, 15) as u16
4322    }
4323
4324    /// Level number.
4325    pub fn level_number(&self) -> u8 {
4326        get_bits(self.ecx, 0, 7) as u8
4327    }
4328
4329    // Level type.
4330    pub fn level_type(&self) -> TopologyType {
4331        match get_bits(self.ecx, 8, 15) {
4332            0 => TopologyType::Invalid,
4333            1 => TopologyType::SMT,
4334            2 => TopologyType::Core,
4335            3 => TopologyType::Module,
4336            4 => TopologyType::Tile,
4337            5 => TopologyType::Die,
4338            _ => unreachable!(),
4339        }
4340    }
4341
4342    /// x2APIC ID the current logical processor. (Bits 31-00)
4343    pub fn x2apic_id(&self) -> u32 {
4344        self.edx
4345    }
4346
4347    /// Number of bits to shift right on x2APIC ID to get a unique topology ID of the next level type. (Bits 04-00)
4348    /// All logical processors with the same next level ID share current level.
4349    pub fn shift_right_for_next_apic_id(&self) -> u32 {
4350        get_bits(self.eax, 0, 4)
4351    }
4352}
4353
4354/// What type of core we have at this level in the topology (real CPU or hyper-threaded).
4355#[derive(PartialEq, Eq, Debug)]
4356pub enum TopologyType {
4357    Invalid = 0,
4358    /// Hyper-thread (Simultaneous multithreading)
4359    SMT = 1,
4360    Core = 2,
4361    Module = 3,
4362    Tile = 4,
4363    Die = 5,
4364}
4365
4366impl fmt::Display for TopologyType {
4367    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
4368        let data = match self {
4369            TopologyType::Invalid => "Invalid",
4370            TopologyType::SMT => "SMT",
4371            TopologyType::Core => "Core",
4372            TopologyType::Module => "Module",
4373            TopologyType::Tile => "Tile",
4374            TopologyType::Die => "Die",
4375        };
4376
4377        f.write_str(data)
4378    }
4379}
4380
4381impl<R: CpuIdReader> Iterator for ExtendedTopologyIter<R> {
4382    type Item = ExtendedTopologyLevel;
4383
4384    fn next(&mut self) -> Option<ExtendedTopologyLevel> {
4385        let res = if self.is_v2 {
4386            self.read.cpuid2(EAX_EXTENDED_TOPOLOGY_INFO_V2, self.level)
4387        } else {
4388            self.read.cpuid2(EAX_EXTENDED_TOPOLOGY_INFO, self.level)
4389        };
4390        self.level += 1;
4391
4392        let et = ExtendedTopologyLevel {
4393            eax: res.eax,
4394            ebx: res.ebx,
4395            ecx: res.ecx,
4396            edx: res.edx,
4397        };
4398
4399        match et.level_type() {
4400            TopologyType::Invalid => None,
4401            _ => Some(et),
4402        }
4403    }
4404}
4405
4406impl<R: CpuIdReader> Debug for ExtendedTopologyIter<R> {
4407    fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
4408        let mut debug = f.debug_list();
4409        self.clone().for_each(|ref item| {
4410            debug.entry(item);
4411        });
4412        debug.finish()
4413    }
4414}
4415
4416bitflags! {
4417    #[repr(transparent)]
4418    #[derive(Debug, Clone, Copy, PartialEq, Eq)]
4419    struct ExtendedStateInfoXCR0Flags: u32 {
4420        /// legacy x87 (Bit 00).
4421        const LEGACY_X87 = 1 << 0;
4422
4423        /// 128-bit SSE (Bit 01).
4424        const SSE128 = 1 << 1;
4425
4426        /// 256-bit AVX (Bit 02).
4427        const AVX256 = 1 << 2;
4428
4429        /// MPX BNDREGS (Bit 03).
4430        const MPX_BNDREGS = 1 << 3;
4431
4432        /// MPX BNDCSR (Bit 04).
4433        const MPX_BNDCSR = 1 << 4;
4434
4435        /// AVX512 OPMASK (Bit 05).
4436        const AVX512_OPMASK = 1 << 5;
4437
4438        /// AVX ZMM Hi256 (Bit 06).
4439        const AVX512_ZMM_HI256 = 1 << 6;
4440
4441        /// AVX 512 ZMM Hi16 (Bit 07).
4442        const AVX512_ZMM_HI16 = 1 << 7;
4443
4444        /// PKRU state (Bit 09).
4445        const PKRU = 1 << 9;
4446
4447        /// IA32_XSS HDC State (Bit 13).
4448        const IA32_XSS_HDC = 1 << 13;
4449
4450        /// AMX TILECFG state (Bit 17)
4451        const AMX_TILECFG = 1 << 17;
4452
4453        /// AMX TILEDATA state (Bit 17)
4454        const AMX_TILEDATA = 1 << 18;
4455    }
4456}
4457
4458bitflags! {
4459    #[repr(transparent)]
4460    #[derive(Debug, Clone, Copy, PartialEq, Eq)]
4461    struct ExtendedStateInfoXSSFlags: u32 {
4462        /// IA32_XSS PT (Trace Packet) State (Bit 08).
4463        const PT = 1 << 8;
4464
4465        /// IA32_XSS PASID state (Bit 10)
4466        const PASID = 1 << 10;
4467
4468        /// IA32_XSS CET user state (Bit 11)
4469        const CET_USER = 1 << 11;
4470
4471        /// IA32_XSS CET supervisor state (Bit 12)
4472        const CET_SUPERVISOR = 1 << 12;
4473
4474        /// IA32_XSS HDC State (Bit 13).
4475        const HDC = 1 << 13;
4476
4477        /// IA32_XSS UINTR state (Bit 14)
4478        const UINTR = 1 << 14;
4479
4480        /// IA32_XSS LBR state (Bit 15)
4481        const LBR = 1 << 15;
4482
4483        /// IA32_XSS HWP state (Bit 16)
4484        const HWP = 1 << 16;
4485    }
4486}
4487
4488/// Information for saving/restoring extended register state (LEAF=0x0D).
4489///
4490/// # Platforms
4491/// ✅ AMD ✅ Intel
4492pub struct ExtendedStateInfo<R: CpuIdReader> {
4493    read: R,
4494    eax: ExtendedStateInfoXCR0Flags,
4495    ebx: u32,
4496    ecx: u32,
4497    _edx: u32,
4498    eax1: u32,
4499    ebx1: u32,
4500    ecx1: ExtendedStateInfoXSSFlags,
4501    _edx1: u32,
4502}
4503
4504impl<F: CpuIdReader> ExtendedStateInfo<F> {
4505    check_flag!(
4506        doc = "Support for legacy x87 in XCR0.",
4507        xcr0_supports_legacy_x87,
4508        eax,
4509        ExtendedStateInfoXCR0Flags::LEGACY_X87
4510    );
4511
4512    check_flag!(
4513        doc = "Support for SSE 128-bit in XCR0.",
4514        xcr0_supports_sse_128,
4515        eax,
4516        ExtendedStateInfoXCR0Flags::SSE128
4517    );
4518
4519    check_flag!(
4520        doc = "Support for AVX 256-bit in XCR0.",
4521        xcr0_supports_avx_256,
4522        eax,
4523        ExtendedStateInfoXCR0Flags::AVX256
4524    );
4525
4526    check_flag!(
4527        doc = "Support for MPX BNDREGS in XCR0.",
4528        xcr0_supports_mpx_bndregs,
4529        eax,
4530        ExtendedStateInfoXCR0Flags::MPX_BNDREGS
4531    );
4532
4533    check_flag!(
4534        doc = "Support for MPX BNDCSR in XCR0.",
4535        xcr0_supports_mpx_bndcsr,
4536        eax,
4537        ExtendedStateInfoXCR0Flags::MPX_BNDCSR
4538    );
4539
4540    check_flag!(
4541        doc = "Support for AVX512 OPMASK in XCR0.",
4542        xcr0_supports_avx512_opmask,
4543        eax,
4544        ExtendedStateInfoXCR0Flags::AVX512_OPMASK
4545    );
4546
4547    check_flag!(
4548        doc = "Support for AVX512 ZMM Hi256 XCR0.",
4549        xcr0_supports_avx512_zmm_hi256,
4550        eax,
4551        ExtendedStateInfoXCR0Flags::AVX512_ZMM_HI256
4552    );
4553
4554    check_flag!(
4555        doc = "Support for AVX512 ZMM Hi16 in XCR0.",
4556        xcr0_supports_avx512_zmm_hi16,
4557        eax,
4558        ExtendedStateInfoXCR0Flags::AVX512_ZMM_HI16
4559    );
4560
4561    check_flag!(
4562        doc = "Support for PKRU in XCR0.",
4563        xcr0_supports_pkru,
4564        eax,
4565        ExtendedStateInfoXCR0Flags::PKRU
4566    );
4567
4568    check_flag!(
4569        doc = "Support for PT in IA32_XSS.",
4570        ia32_xss_supports_pt,
4571        ecx1,
4572        ExtendedStateInfoXSSFlags::PT
4573    );
4574
4575    check_flag!(
4576        doc = "Support for HDC in IA32_XSS.",
4577        ia32_xss_supports_hdc,
4578        ecx1,
4579        ExtendedStateInfoXSSFlags::HDC
4580    );
4581
4582    /// Maximum size (bytes, from the beginning of the XSAVE/XRSTOR save area) required by
4583    /// enabled features in XCR0. May be different than ECX if some features at the end of the XSAVE save area
4584    /// are not enabled.
4585    pub fn xsave_area_size_enabled_features(&self) -> u32 {
4586        self.ebx
4587    }
4588
4589    /// Maximum size (bytes, from the beginning of the XSAVE/XRSTOR save area) of the
4590    /// XSAVE/XRSTOR save area required by all supported features in the processor,
4591    /// i.e all the valid bit fields in XCR0.
4592    pub fn xsave_area_size_supported_features(&self) -> u32 {
4593        self.ecx
4594    }
4595
4596    /// CPU has xsaveopt feature.
4597    pub fn has_xsaveopt(&self) -> bool {
4598        self.eax1 & 0x1 > 0
4599    }
4600
4601    /// Supports XSAVEC and the compacted form of XRSTOR if set.
4602    pub fn has_xsavec(&self) -> bool {
4603        self.eax1 & 0b10 > 0
4604    }
4605
4606    /// Supports XGETBV with ECX = 1 if set.
4607    pub fn has_xgetbv(&self) -> bool {
4608        self.eax1 & 0b100 > 0
4609    }
4610
4611    /// Supports XSAVES/XRSTORS and IA32_XSS if set.
4612    pub fn has_xsaves_xrstors(&self) -> bool {
4613        self.eax1 & 0b1000 > 0
4614    }
4615
4616    /// The size in bytes of the XSAVE area containing all states enabled by XCRO | IA32_XSS.
4617    pub fn xsave_size(&self) -> u32 {
4618        self.ebx1
4619    }
4620
4621    /// Iterator over extended state enumeration levels >= 2.
4622    pub fn iter(&self) -> ExtendedStateIter<F> {
4623        ExtendedStateIter {
4624            read: self.read.clone(),
4625            level: 1,
4626            supported_xcr0: self.eax.bits(),
4627            supported_xss: self.ecx1.bits(),
4628        }
4629    }
4630}
4631
4632impl<R: CpuIdReader> Debug for ExtendedStateInfo<R> {
4633    fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
4634        f.debug_struct("ExtendedStateInfo")
4635            .field("eax", &self.eax)
4636            .field("ecx1", &self.ecx1)
4637            .field(
4638                "xsave_area_size_enabled_features",
4639                &self.xsave_area_size_enabled_features(),
4640            )
4641            .field(
4642                "xsave_area_size_supported_features",
4643                &self.xsave_area_size_supported_features(),
4644            )
4645            .field("has_xsaveopt", &self.has_xsaveopt())
4646            .field("has_xsavec", &self.has_xsavec())
4647            .field("has_xgetbv", &self.has_xgetbv())
4648            .field("has_xsaves_xrstors", &self.has_xsaves_xrstors())
4649            .field("xsave_size", &self.xsave_size())
4650            .field("extended_state_iter", &self.iter())
4651            .finish()
4652    }
4653}
4654
4655/// Yields [ExtendedState] structs.
4656#[derive(Clone)]
4657pub struct ExtendedStateIter<R: CpuIdReader> {
4658    read: R,
4659    level: u32,
4660    supported_xcr0: u32,
4661    supported_xss: u32,
4662}
4663
4664/// When CPUID executes with EAX set to 0DH and ECX = n (n > 1, and is a valid
4665/// sub-leaf index), the processor returns information about the size and offset
4666/// of each processor extended state save area within the XSAVE/XRSTOR area.
4667///
4668/// The iterator goes over the valid sub-leaves and obtain size and offset
4669/// information for each processor extended state save area:
4670impl<R: CpuIdReader> Iterator for ExtendedStateIter<R> {
4671    type Item = ExtendedState;
4672
4673    fn next(&mut self) -> Option<ExtendedState> {
4674        self.level += 1;
4675        if self.level > 31 {
4676            return None;
4677        }
4678
4679        let bit = 1 << self.level;
4680        if (self.supported_xcr0 & bit > 0) || (self.supported_xss & bit > 0) {
4681            let res = self.read.cpuid2(EAX_EXTENDED_STATE_INFO, self.level);
4682            return Some(ExtendedState {
4683                subleaf: self.level,
4684                eax: res.eax,
4685                ebx: res.ebx,
4686                ecx: res.ecx,
4687            });
4688        }
4689
4690        self.next()
4691    }
4692}
4693
4694impl<R: CpuIdReader> Debug for ExtendedStateIter<R> {
4695    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
4696        let mut debug = f.debug_list();
4697        self.clone().for_each(|ref item| {
4698            debug.entry(item);
4699        });
4700        debug.finish()
4701    }
4702}
4703
4704/// What kidn of extended register state this is.
4705#[derive(PartialEq, Eq, Debug)]
4706#[repr(u32)]
4707pub enum ExtendedRegisterType {
4708    Avx,
4709    MpxBndregs,
4710    MpxBndcsr,
4711    Avx512Opmask,
4712    Avx512ZmmHi256,
4713    Avx512ZmmHi16,
4714    Pt,
4715    Pkru,
4716    Hdc,
4717    Unknown(u32),
4718}
4719
4720impl From<u32> for ExtendedRegisterType {
4721    fn from(value: u32) -> ExtendedRegisterType {
4722        match value {
4723            0x2 => ExtendedRegisterType::Avx,
4724            0x3 => ExtendedRegisterType::MpxBndregs,
4725            0x4 => ExtendedRegisterType::MpxBndcsr,
4726            0x5 => ExtendedRegisterType::Avx512Opmask,
4727            0x6 => ExtendedRegisterType::Avx512ZmmHi256,
4728            0x7 => ExtendedRegisterType::Avx512ZmmHi16,
4729            0x8 => ExtendedRegisterType::Pt,
4730            0x9 => ExtendedRegisterType::Pkru,
4731            0xd => ExtendedRegisterType::Hdc,
4732            x => ExtendedRegisterType::Unknown(x),
4733        }
4734    }
4735}
4736
4737impl fmt::Display for ExtendedRegisterType {
4738    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
4739        let data = match self {
4740            ExtendedRegisterType::Avx => "AVX/YMM",
4741            ExtendedRegisterType::MpxBndregs => "MPX BNDREGS",
4742            ExtendedRegisterType::MpxBndcsr => "MPX BNDCSR",
4743            ExtendedRegisterType::Avx512Opmask => "AVX-512 opmask",
4744            ExtendedRegisterType::Avx512ZmmHi256 => "AVX-512 ZMM_Hi256",
4745            ExtendedRegisterType::Avx512ZmmHi16 => "AVX-512 Hi16_ZMM",
4746            ExtendedRegisterType::Pkru => "PKRU",
4747            ExtendedRegisterType::Pt => "PT",
4748            ExtendedRegisterType::Hdc => "HDC",
4749            ExtendedRegisterType::Unknown(t) => {
4750                return write!(f, "Unknown({})", t);
4751            }
4752        };
4753
4754        f.write_str(data)
4755    }
4756}
4757
4758/// Where the extended register state is stored.
4759#[derive(PartialEq, Eq, Debug)]
4760pub enum ExtendedRegisterStateLocation {
4761    Xcr0,
4762    Ia32Xss,
4763}
4764
4765impl fmt::Display for ExtendedRegisterStateLocation {
4766    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
4767        let data = match self {
4768            ExtendedRegisterStateLocation::Xcr0 => "XCR0 (user state)",
4769            ExtendedRegisterStateLocation::Ia32Xss => "IA32_XSS (supervisor state)",
4770        };
4771
4772        f.write_str(data)
4773    }
4774}
4775
4776/// ExtendedState subleaf structure for things that need to be restored.
4777pub struct ExtendedState {
4778    pub subleaf: u32,
4779    eax: u32,
4780    ebx: u32,
4781    ecx: u32,
4782}
4783
4784impl ExtendedState {
4785    /// Returns which register this specific extended subleaf contains information for.
4786    pub fn register(&self) -> ExtendedRegisterType {
4787        self.subleaf.into()
4788    }
4789
4790    /// The size in bytes (from the offset specified in EBX) of the save area
4791    /// for an extended state feature associated with a valid sub-leaf index, n.
4792    /// This field reports 0 if the sub-leaf index, n, is invalid.
4793    pub fn size(&self) -> u32 {
4794        self.eax
4795    }
4796
4797    /// The offset in bytes of this extended state components save area
4798    /// from the beginning of the XSAVE/XRSTOR area.
4799    pub fn offset(&self) -> u32 {
4800        self.ebx
4801    }
4802
4803    pub fn location(&self) -> ExtendedRegisterStateLocation {
4804        if self.is_in_xcr0() {
4805            ExtendedRegisterStateLocation::Xcr0
4806        } else {
4807            ExtendedRegisterStateLocation::Ia32Xss
4808        }
4809    }
4810
4811    /// True if the bit n (corresponding to the sub-leaf index)
4812    /// is supported in the IA32_XSS MSR;
4813    ///
4814    /// # Deprecation note
4815    /// This will likely be removed in the future. Use `location()` instead.
4816    pub fn is_in_ia32_xss(&self) -> bool {
4817        self.ecx & 0b1 > 0
4818    }
4819
4820    /// True if bit n is supported in XCR0.
4821    ///
4822    /// # Deprecation note
4823    /// This will likely be removed in the future. Use `location()` instead.
4824    pub fn is_in_xcr0(&self) -> bool {
4825        self.ecx & 0b1 == 0
4826    }
4827
4828    /// Returns true when the compacted format of an XSAVE area is used,
4829    /// this extended state component located on the next 64-byte
4830    /// boundary following the preceding state component
4831    /// (otherwise, it is located immediately following the preceding state component).
4832    pub fn is_compacted_format(&self) -> bool {
4833        self.ecx & 0b10 > 0
4834    }
4835}
4836
4837impl Debug for ExtendedState {
4838    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
4839        f.debug_struct("ExtendedState")
4840            .field("size", &self.size())
4841            .field("offset", &self.offset())
4842            .field("is_in_ia32_xss", &self.is_in_ia32_xss())
4843            .field("is_in_xcr0", &self.is_in_xcr0())
4844            .field("is_compacted_format", &self.is_compacted_format())
4845            .finish()
4846    }
4847}
4848
4849/// Intel Resource Director Technology RDT (LEAF=0x0F).
4850///
4851/// Monitoring Enumeration Sub-leaf (EAX = 0FH, ECX = 0 and ECX = 1)
4852/// # Platforms
4853/// ❌ AMD ✅ Intel
4854pub struct RdtMonitoringInfo<R: CpuIdReader> {
4855    read: R,
4856    ebx: u32,
4857    edx: u32,
4858}
4859
4860impl<R: CpuIdReader> RdtMonitoringInfo<R> {
4861    /// Maximum range (zero-based) of RMID within this physical processor of all types.
4862    pub fn rmid_range(&self) -> u32 {
4863        self.ebx
4864    }
4865
4866    check_bit_fn!(
4867        doc = "Supports L3 Cache Intel RDT Monitoring.",
4868        has_l3_monitoring,
4869        edx,
4870        1
4871    );
4872
4873    /// L3 Cache Monitoring.
4874    pub fn l3_monitoring(&self) -> Option<L3MonitoringInfo> {
4875        if self.has_l3_monitoring() {
4876            let res = self.read.cpuid2(EAX_RDT_MONITORING, 1);
4877            Some(L3MonitoringInfo {
4878                ebx: res.ebx,
4879                ecx: res.ecx,
4880                edx: res.edx,
4881            })
4882        } else {
4883            None
4884        }
4885    }
4886}
4887
4888impl<R: CpuIdReader> Debug for RdtMonitoringInfo<R> {
4889    fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
4890        f.debug_struct("RdtMonitoringInfo")
4891            .field("rmid_range", &self.rmid_range())
4892            .field("l3_monitoring", &self.l3_monitoring())
4893            .finish()
4894    }
4895}
4896
4897/// Information about L3 cache monitoring.
4898pub struct L3MonitoringInfo {
4899    ebx: u32,
4900    ecx: u32,
4901    edx: u32,
4902}
4903
4904impl L3MonitoringInfo {
4905    /// Conversion factor from reported IA32_QM_CTR value to occupancy metric (bytes).
4906    pub fn conversion_factor(&self) -> u32 {
4907        self.ebx
4908    }
4909
4910    /// Maximum range (zero-based) of RMID of L3.
4911    pub fn maximum_rmid_range(&self) -> u32 {
4912        self.ecx
4913    }
4914
4915    check_bit_fn!(
4916        doc = "Supports occupancy monitoring.",
4917        has_occupancy_monitoring,
4918        edx,
4919        0
4920    );
4921
4922    check_bit_fn!(
4923        doc = "Supports total bandwidth monitoring.",
4924        has_total_bandwidth_monitoring,
4925        edx,
4926        1
4927    );
4928
4929    check_bit_fn!(
4930        doc = "Supports local bandwidth monitoring.",
4931        has_local_bandwidth_monitoring,
4932        edx,
4933        2
4934    );
4935}
4936
4937impl Debug for L3MonitoringInfo {
4938    fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
4939        f.debug_struct("L3MonitoringInfo")
4940            .field("conversion_factor", &self.conversion_factor())
4941            .field("maximum_rmid_range", &self.maximum_rmid_range())
4942            .finish()
4943    }
4944}
4945
4946/// Quality of service enforcement information (LEAF=0x10).
4947///
4948/// # Platforms
4949/// ❌ AMD ✅ Intel
4950pub struct RdtAllocationInfo<R: CpuIdReader> {
4951    read: R,
4952    ebx: u32,
4953}
4954
4955impl<R: CpuIdReader> RdtAllocationInfo<R> {
4956    check_bit_fn!(doc = "Supports L3 Cache Allocation.", has_l3_cat, ebx, 1);
4957
4958    check_bit_fn!(doc = "Supports L2 Cache Allocation.", has_l2_cat, ebx, 2);
4959
4960    check_bit_fn!(
4961        doc = "Supports Memory Bandwidth Allocation.",
4962        has_memory_bandwidth_allocation,
4963        ebx,
4964        3
4965    );
4966
4967    /// L3 Cache Allocation Information.
4968    pub fn l3_cat(&self) -> Option<L3CatInfo> {
4969        if self.has_l3_cat() {
4970            let res = self.read.cpuid2(EAX_RDT_ALLOCATION, 1);
4971            Some(L3CatInfo {
4972                eax: res.eax,
4973                ebx: res.ebx,
4974                ecx: res.ecx,
4975                edx: res.edx,
4976            })
4977        } else {
4978            None
4979        }
4980    }
4981
4982    /// L2 Cache Allocation Information.
4983    pub fn l2_cat(&self) -> Option<L2CatInfo> {
4984        if self.has_l2_cat() {
4985            let res = self.read.cpuid2(EAX_RDT_ALLOCATION, 2);
4986            Some(L2CatInfo {
4987                eax: res.eax,
4988                ebx: res.ebx,
4989                edx: res.edx,
4990            })
4991        } else {
4992            None
4993        }
4994    }
4995
4996    /// Memory Bandwidth Allocation Information.
4997    pub fn memory_bandwidth_allocation(&self) -> Option<MemBwAllocationInfo> {
4998        if self.has_memory_bandwidth_allocation() {
4999            let res = self.read.cpuid2(EAX_RDT_ALLOCATION, 3);
5000            Some(MemBwAllocationInfo {
5001                eax: res.eax,
5002                ecx: res.ecx,
5003                edx: res.edx,
5004            })
5005        } else {
5006            None
5007        }
5008    }
5009}
5010
5011impl<R: CpuIdReader> Debug for RdtAllocationInfo<R> {
5012    fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
5013        f.debug_struct("RdtAllocationInfo")
5014            .field("l3_cat", &self.l3_cat())
5015            .field("l2_cat", &self.l2_cat())
5016            .field(
5017                "memory_bandwidth_allocation",
5018                &self.memory_bandwidth_allocation(),
5019            )
5020            .finish()
5021    }
5022}
5023
5024/// L3 Cache Allocation Technology Enumeration Sub-leaf (LEAF=0x10, SUBLEAF=1).
5025pub struct L3CatInfo {
5026    eax: u32,
5027    ebx: u32,
5028    ecx: u32,
5029    edx: u32,
5030}
5031
5032impl L3CatInfo {
5033    /// Length of the capacity bit mask.
5034    pub fn capacity_mask_length(&self) -> u8 {
5035        (get_bits(self.eax, 0, 4) + 1) as u8
5036    }
5037
5038    /// Bit-granular map of isolation/contention of allocation units.
5039    pub fn isolation_bitmap(&self) -> u32 {
5040        self.ebx
5041    }
5042
5043    /// Highest COS number supported for this Leaf.
5044    pub fn highest_cos(&self) -> u16 {
5045        get_bits(self.edx, 0, 15) as u16
5046    }
5047
5048    check_bit_fn!(
5049        doc = "Is Code and Data Prioritization Technology supported?",
5050        has_code_data_prioritization,
5051        ecx,
5052        2
5053    );
5054}
5055
5056impl Debug for L3CatInfo {
5057    fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
5058        f.debug_struct("L3CatInfo")
5059            .field("capacity_mask_length", &self.capacity_mask_length())
5060            .field("isolation_bitmap", &self.isolation_bitmap())
5061            .field("highest_cos", &self.highest_cos())
5062            .finish()
5063    }
5064}
5065
5066/// L2 Cache Allocation Technology Enumeration Sub-leaf (LEAF=0x10, SUBLEAF=2).
5067#[derive(Eq, PartialEq)]
5068pub struct L2CatInfo {
5069    eax: u32,
5070    ebx: u32,
5071    edx: u32,
5072}
5073
5074impl L2CatInfo {
5075    /// Length of the capacity bit mask.
5076    pub fn capacity_mask_length(&self) -> u8 {
5077        (get_bits(self.eax, 0, 4) + 1) as u8
5078    }
5079
5080    /// Bit-granular map of isolation/contention of allocation units.
5081    pub fn isolation_bitmap(&self) -> u32 {
5082        self.ebx
5083    }
5084
5085    /// Highest COS number supported for this Leaf.
5086    pub fn highest_cos(&self) -> u16 {
5087        get_bits(self.edx, 0, 15) as u16
5088    }
5089}
5090
5091impl Debug for L2CatInfo {
5092    fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
5093        f.debug_struct("L2CatInfo")
5094            .field("capacity_mask_length", &self.capacity_mask_length())
5095            .field("isolation_bitmap", &self.isolation_bitmap())
5096            .field("highest_cos", &self.highest_cos())
5097            .finish()
5098    }
5099}
5100
5101/// Memory Bandwidth Allocation Enumeration Sub-leaf (LEAF=0x10, SUBLEAF=3).
5102#[derive(Eq, PartialEq)]
5103pub struct MemBwAllocationInfo {
5104    eax: u32,
5105    ecx: u32,
5106    edx: u32,
5107}
5108
5109impl MemBwAllocationInfo {
5110    /// Reports the maximum MBA throttling value supported for the corresponding ResID.
5111    pub fn max_hba_throttling(&self) -> u16 {
5112        (get_bits(self.eax, 0, 11) + 1) as u16
5113    }
5114
5115    /// Highest COS number supported for this Leaf.
5116    pub fn highest_cos(&self) -> u16 {
5117        get_bits(self.edx, 0, 15) as u16
5118    }
5119
5120    check_bit_fn!(
5121        doc = "Reports whether the response of the delay values is linear.",
5122        has_linear_response_delay,
5123        ecx,
5124        2
5125    );
5126}
5127
5128impl Debug for MemBwAllocationInfo {
5129    fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
5130        f.debug_struct("MemBwAllocationInfo")
5131            .field("max_hba_throttling", &self.max_hba_throttling())
5132            .field("highest_cos", &self.highest_cos())
5133            .field(
5134                "has_linear_response_delay",
5135                &self.has_linear_response_delay(),
5136            )
5137            .finish()
5138    }
5139}
5140
5141/// Intel SGX Capability Enumeration Leaf (LEAF=0x12).
5142///
5143/// Two sub-leafs: (EAX = 12H, ECX = 0 and ECX = 1)
5144///
5145/// # Platforms
5146/// ❌ AMD ✅ Intel
5147pub struct SgxInfo<R: CpuIdReader> {
5148    read: R,
5149    eax: u32,
5150    ebx: u32,
5151    _ecx: u32,
5152    edx: u32,
5153    eax1: u32,
5154    ebx1: u32,
5155    ecx1: u32,
5156    edx1: u32,
5157}
5158
5159impl<F: CpuIdReader> SgxInfo<F> {
5160    check_bit_fn!(doc = "Has SGX1 support.", has_sgx1, eax, 0);
5161    check_bit_fn!(doc = "Has SGX2 support.", has_sgx2, eax, 1);
5162
5163    check_bit_fn!(
5164        doc = "Supports ENCLV instruction leaves EINCVIRTCHILD, EDECVIRTCHILD, and ESETCONTEXT.",
5165        has_enclv_leaves_einvirtchild_edecvirtchild_esetcontext,
5166        eax,
5167        5
5168    );
5169
5170    check_bit_fn!(
5171        doc = "Supports ENCLS instruction leaves ETRACKC, ERDINFO, ELDBC, and ELDUC.",
5172        has_encls_leaves_etrackc_erdinfo_eldbc_elduc,
5173        eax,
5174        6
5175    );
5176
5177    /// Bit vector of supported extended SGX features.
5178    pub fn miscselect(&self) -> u32 {
5179        self.ebx
5180    }
5181
5182    ///  The maximum supported enclave size in non-64-bit mode is 2^retval.
5183    pub fn max_enclave_size_non_64bit(&self) -> u8 {
5184        get_bits(self.edx, 0, 7) as u8
5185    }
5186
5187    ///  The maximum supported enclave size in 64-bit mode is 2^retval.
5188    pub fn max_enclave_size_64bit(&self) -> u8 {
5189        get_bits(self.edx, 8, 15) as u8
5190    }
5191
5192    /// Reports the valid bits of SECS.ATTRIBUTES\[127:0\] that software can set with ECREATE.
5193    pub fn secs_attributes(&self) -> (u64, u64) {
5194        let lower = self.eax1 as u64 | (self.ebx1 as u64) << 32;
5195        let upper = self.ecx1 as u64 | (self.edx1 as u64) << 32;
5196        (lower, upper)
5197    }
5198    /// Iterator over SGX sub-leafs.
5199    pub fn iter(&self) -> SgxSectionIter<F> {
5200        SgxSectionIter {
5201            read: self.read.clone(),
5202            current: 2,
5203        }
5204    }
5205}
5206
5207impl<R: CpuIdReader> Debug for SgxInfo<R> {
5208    fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
5209        f.debug_struct("SgxInfo")
5210            .field("has_sgx1", &self.has_sgx1())
5211            .field("has_sgx2", &self.has_sgx2())
5212            .field("miscselect", &self.miscselect())
5213            .field(
5214                "max_enclave_size_non_64bit",
5215                &self.max_enclave_size_non_64bit(),
5216            )
5217            .field("max_enclave_size_64bit", &self.max_enclave_size_64bit())
5218            .field(
5219                "has_encls_leaves_etrackc_erdinfo_eldbc_elduc",
5220                &self.has_encls_leaves_etrackc_erdinfo_eldbc_elduc(),
5221            )
5222            .field(
5223                "has_enclv_leaves_einvirtchild_edecvirtchild_esetcontext",
5224                &self.has_enclv_leaves_einvirtchild_edecvirtchild_esetcontext(),
5225            )
5226            .field("sgx_section_iter", &self.iter())
5227            .finish()
5228    }
5229}
5230
5231/// Iterator over the SGX sub-leafs (ECX >= 2).
5232#[derive(Clone)]
5233pub struct SgxSectionIter<R: CpuIdReader> {
5234    read: R,
5235    current: u32,
5236}
5237
5238impl<R: CpuIdReader> Iterator for SgxSectionIter<R> {
5239    type Item = SgxSectionInfo;
5240
5241    fn next(&mut self) -> Option<SgxSectionInfo> {
5242        let res = self.read.cpuid2(EAX_SGX, self.current);
5243        self.current += 1;
5244        match get_bits(res.eax, 0, 3) {
5245            0b0001 => Some(SgxSectionInfo::Epc(EpcSection {
5246                eax: res.eax,
5247                ebx: res.ebx,
5248                ecx: res.ecx,
5249                edx: res.edx,
5250            })),
5251            _ => None,
5252        }
5253    }
5254}
5255
5256impl<R: CpuIdReader> Debug for SgxSectionIter<R> {
5257    fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
5258        let mut debug = f.debug_list();
5259        self.clone().for_each(|ref item| {
5260            debug.entry(item);
5261        });
5262        debug.finish()
5263    }
5264}
5265
5266/// Intel SGX EPC Enumeration Leaf
5267///
5268/// Sub-leaves 2 or higher.
5269#[derive(Debug)]
5270pub enum SgxSectionInfo {
5271    // This would be nice: https://github.com/rust-lang/rfcs/pull/1450
5272    Epc(EpcSection),
5273}
5274
5275/// EBX:EAX and EDX:ECX provide information on the Enclave Page Cache (EPC) section
5276#[derive(Debug)]
5277pub struct EpcSection {
5278    eax: u32,
5279    ebx: u32,
5280    ecx: u32,
5281    edx: u32,
5282}
5283
5284impl EpcSection {
5285    /// The physical address of the base of the EPC section
5286    pub fn physical_base(&self) -> u64 {
5287        let lower = (get_bits(self.eax, 12, 31) << 12) as u64;
5288        let upper = (get_bits(self.ebx, 0, 19) as u64) << 32;
5289        lower | upper
5290    }
5291
5292    /// Size of the corresponding EPC section within the Processor Reserved Memory.
5293    pub fn size(&self) -> u64 {
5294        let lower = (get_bits(self.ecx, 12, 31) << 12) as u64;
5295        let upper = (get_bits(self.edx, 0, 19) as u64) << 32;
5296        lower | upper
5297    }
5298}
5299
5300/// Intel Processor Trace Information (LEAF=0x14).
5301///
5302/// # Platforms
5303/// ❌ AMD ✅ Intel
5304pub struct ProcessorTraceInfo {
5305    _eax: u32,
5306    ebx: u32,
5307    ecx: u32,
5308    _edx: u32,
5309    leaf1: Option<CpuIdResult>,
5310}
5311
5312impl ProcessorTraceInfo {
5313    // EBX features
5314    check_bit_fn!(
5315        doc = "If true, Indicates that IA32_RTIT_CTL.CR3Filter can be set to 1, and \
5316               that IA32_RTIT_CR3_MATCH MSR can be accessed.",
5317        has_rtit_cr3_match,
5318        ebx,
5319        0
5320    );
5321    check_bit_fn!(
5322        doc = "If true, Indicates support of Configurable PSB and Cycle-Accurate Mode.",
5323        has_configurable_psb_and_cycle_accurate_mode,
5324        ebx,
5325        1
5326    );
5327    check_bit_fn!(
5328        doc = "If true, Indicates support of IP Filtering, TraceStop filtering, and \
5329               preservation of Intel PT MSRs across warm reset.",
5330        has_ip_tracestop_filtering,
5331        ebx,
5332        2
5333    );
5334    check_bit_fn!(
5335        doc = "If true, Indicates support of MTC timing packet and suppression of \
5336               COFI-based packets.",
5337        has_mtc_timing_packet_coefi_suppression,
5338        ebx,
5339        3
5340    );
5341
5342    check_bit_fn!(
5343        doc = "Indicates support of PTWRITE. Writes can set IA32_RTIT_CTL\\[12\\] (PTWEn \
5344               and IA32_RTIT_CTL\\[5\\] (FUPonPTW), and PTWRITE can generate packets",
5345        has_ptwrite,
5346        ebx,
5347        4
5348    );
5349
5350    check_bit_fn!(
5351        doc = "Support of Power Event Trace. Writes can set IA32_RTIT_CTL\\[4\\] (PwrEvtEn) \
5352               enabling Power Event Trace packet generation.",
5353        has_power_event_trace,
5354        ebx,
5355        5
5356    );
5357
5358    // ECX features
5359    check_bit_fn!(
5360        doc = "If true, Tracing can be enabled with IA32_RTIT_CTL.ToPA = 1, hence \
5361               utilizing the ToPA output scheme; IA32_RTIT_OUTPUT_BASE and \
5362               IA32_RTIT_OUTPUT_MASK_PTRS MSRs can be accessed.",
5363        has_topa,
5364        ecx,
5365        0
5366    );
5367    check_bit_fn!(
5368        doc = "If true, ToPA tables can hold any number of output entries, up to the \
5369               maximum allowed by the MaskOrTableOffset field of \
5370               IA32_RTIT_OUTPUT_MASK_PTRS.",
5371        has_topa_maximum_entries,
5372        ecx,
5373        1
5374    );
5375    check_bit_fn!(
5376        doc = "If true, Indicates support of Single-Range Output scheme.",
5377        has_single_range_output_scheme,
5378        ecx,
5379        2
5380    );
5381    check_bit_fn!(
5382        doc = "If true, Indicates support of output to Trace Transport subsystem.",
5383        has_trace_transport_subsystem,
5384        ecx,
5385        3
5386    );
5387    check_bit_fn!(
5388        doc = "If true, Generated packets which contain IP payloads have LIP values, \
5389               which include the CS base component.",
5390        has_lip_with_cs_base,
5391        ecx,
5392        31
5393    );
5394
5395    /// Number of configurable Address Ranges for filtering (Bits 2:0).
5396    pub fn configurable_address_ranges(&self) -> u8 {
5397        self.leaf1.map_or(0, |res| get_bits(res.eax, 0, 2) as u8)
5398    }
5399
5400    /// Bitmap of supported MTC period encodings (Bit 31:16).
5401    pub fn supported_mtc_period_encodings(&self) -> u16 {
5402        self.leaf1.map_or(0, |res| get_bits(res.eax, 16, 31) as u16)
5403    }
5404
5405    /// Bitmap of supported Cycle Threshold value encodings (Bits 15-0).
5406    pub fn supported_cycle_threshold_value_encodings(&self) -> u16 {
5407        self.leaf1.map_or(0, |res| get_bits(res.ebx, 0, 15) as u16)
5408    }
5409
5410    /// Bitmap of supported Configurable PSB frequency encodings (Bit 31:16)
5411    pub fn supported_psb_frequency_encodings(&self) -> u16 {
5412        self.leaf1.map_or(0, |res| get_bits(res.ebx, 16, 31) as u16)
5413    }
5414}
5415
5416impl Debug for ProcessorTraceInfo {
5417    fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
5418        f.debug_struct("ProcessorTraceInfo")
5419            .field(
5420                "configurable_address_ranges",
5421                &self.configurable_address_ranges(),
5422            )
5423            .field(
5424                "supported_mtc_period_encodings",
5425                &self.supported_mtc_period_encodings(),
5426            )
5427            .field(
5428                "supported_cycle_threshold_value_encodings",
5429                &self.supported_cycle_threshold_value_encodings(),
5430            )
5431            .field(
5432                "supported_psb_frequency_encodings",
5433                &self.supported_psb_frequency_encodings(),
5434            )
5435            .finish()
5436    }
5437}
5438
5439/// Time Stamp Counter/Core Crystal Clock Information (LEAF=0x15).
5440///
5441/// # Platforms
5442/// ❌ AMD ✅ Intel
5443pub struct TscInfo {
5444    eax: u32,
5445    ebx: u32,
5446    ecx: u32,
5447}
5448
5449impl fmt::Debug for TscInfo {
5450    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
5451        f.debug_struct("TscInfo")
5452            .field("denominator", &self.denominator())
5453            .field("numerator", &self.numerator())
5454            .field("nominal_frequency", &self.nominal_frequency())
5455            .field("tsc_frequency", &self.tsc_frequency())
5456            .finish()
5457    }
5458}
5459
5460impl TscInfo {
5461    /// An unsigned integer which is the denominator of the TSC/”core crystal clock” ratio.
5462    pub fn denominator(&self) -> u32 {
5463        self.eax
5464    }
5465
5466    /// An unsigned integer which is the numerator of the TSC/”core crystal clock” ratio.
5467    ///
5468    /// If this is 0, the TSC/”core crystal clock” ratio is not enumerated.
5469    pub fn numerator(&self) -> u32 {
5470        self.ebx
5471    }
5472
5473    /// An unsigned integer which is the nominal frequency of the core crystal clock in Hz.
5474    ///
5475    /// If this is 0, the nominal core crystal clock frequency is not enumerated.
5476    pub fn nominal_frequency(&self) -> u32 {
5477        self.ecx
5478    }
5479
5480    /// “TSC frequency” = “core crystal clock frequency” * EBX/EAX.
5481    pub fn tsc_frequency(&self) -> Option<u64> {
5482        // In some case TscInfo is a valid leaf, but the values reported are still 0
5483        // we should avoid a division by zero in case denominator ends up being 0.
5484        if self.nominal_frequency() == 0 || self.numerator() == 0 || self.denominator() == 0 {
5485            return None;
5486        }
5487
5488        Some(self.nominal_frequency() as u64 * self.numerator() as u64 / self.denominator() as u64)
5489    }
5490}
5491
5492/// Processor Frequency Information (LEAF=0x16).
5493///
5494/// # Platforms
5495/// ❌ AMD ✅ Intel
5496pub struct ProcessorFrequencyInfo {
5497    eax: u32,
5498    ebx: u32,
5499    ecx: u32,
5500}
5501
5502impl ProcessorFrequencyInfo {
5503    /// Processor Base Frequency (in MHz).
5504    pub fn processor_base_frequency(&self) -> u16 {
5505        get_bits(self.eax, 0, 15) as u16
5506    }
5507
5508    /// Maximum Frequency (in MHz).
5509    pub fn processor_max_frequency(&self) -> u16 {
5510        get_bits(self.ebx, 0, 15) as u16
5511    }
5512
5513    /// Bus (Reference) Frequency (in MHz).
5514    pub fn bus_frequency(&self) -> u16 {
5515        get_bits(self.ecx, 0, 15) as u16
5516    }
5517}
5518
5519impl fmt::Debug for ProcessorFrequencyInfo {
5520    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
5521        f.debug_struct("ProcessorFrequencyInfo")
5522            .field("processor_base_frequency", &self.processor_base_frequency())
5523            .field("processor_max_frequency", &self.processor_max_frequency())
5524            .field("bus_frequency", &self.bus_frequency())
5525            .finish()
5526    }
5527}
5528
5529/// Deterministic Address Translation Structure Iterator (LEAF=0x18).
5530///
5531/// # Platforms
5532/// ❌ AMD ✅ Intel
5533#[derive(Clone)]
5534pub struct DatIter<R: CpuIdReader> {
5535    read: R,
5536    current: u32,
5537    count: u32,
5538}
5539
5540impl<R: CpuIdReader> Iterator for DatIter<R> {
5541    type Item = DatInfo;
5542
5543    /// Iterate over each sub-leaf with an address translation structure.
5544    fn next(&mut self) -> Option<DatInfo> {
5545        loop {
5546            // Sub-leaf index n is invalid if n exceeds the value that sub-leaf 0 returns in EAX
5547            if self.current > self.count {
5548                return None;
5549            }
5550
5551            let res = self
5552                .read
5553                .cpuid2(EAX_DETERMINISTIC_ADDRESS_TRANSLATION_INFO, self.current);
5554            self.current += 1;
5555
5556            // A sub-leaf index is also invalid if EDX[4:0] returns 0.
5557            if get_bits(res.edx, 0, 4) == 0 {
5558                // Valid sub-leaves do not need to be contiguous or in any particular order.
5559                // A valid sub-leaf may be in a higher input ECX value than an invalid sub-leaf
5560                // or than a valid sub-leaf of a higher or lower-level struc-ture
5561                continue;
5562            }
5563
5564            return Some(DatInfo {
5565                _eax: res.eax,
5566                ebx: res.ebx,
5567                ecx: res.ecx,
5568                edx: res.edx,
5569            });
5570        }
5571    }
5572}
5573
5574impl<R: CpuIdReader> Debug for DatIter<R> {
5575    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
5576        let mut debug = f.debug_list();
5577        self.clone().for_each(|ref item| {
5578            debug.entry(item);
5579        });
5580        debug.finish()
5581    }
5582}
5583
5584/// Deterministic Address Translation Structure
5585pub struct DatInfo {
5586    _eax: u32,
5587    ebx: u32,
5588    ecx: u32,
5589    edx: u32,
5590}
5591
5592impl DatInfo {
5593    check_bit_fn!(
5594        doc = "4K page size entries supported by this structure",
5595        has_4k_entries,
5596        ebx,
5597        0
5598    );
5599
5600    check_bit_fn!(
5601        doc = "2MB page size entries supported by this structure",
5602        has_2mb_entries,
5603        ebx,
5604        1
5605    );
5606
5607    check_bit_fn!(
5608        doc = "4MB page size entries supported by this structure",
5609        has_4mb_entries,
5610        ebx,
5611        2
5612    );
5613
5614    check_bit_fn!(
5615        doc = "1GB page size entries supported by this structure",
5616        has_1gb_entries,
5617        ebx,
5618        3
5619    );
5620
5621    check_bit_fn!(
5622        doc = "Fully associative structure",
5623        is_fully_associative,
5624        edx,
5625        8
5626    );
5627
5628    /// Partitioning (0: Soft partitioning between the logical processors sharing this structure).
5629    pub fn partitioning(&self) -> u8 {
5630        get_bits(self.ebx, 8, 10) as u8
5631    }
5632
5633    /// Ways of associativity.
5634    pub fn ways(&self) -> u16 {
5635        get_bits(self.ebx, 16, 31) as u16
5636    }
5637
5638    /// Number of Sets.
5639    pub fn sets(&self) -> u32 {
5640        self.ecx
5641    }
5642
5643    /// Translation cache type field.
5644    pub fn cache_type(&self) -> DatType {
5645        match get_bits(self.edx, 0, 4) as u8 {
5646            0b00001 => DatType::DataTLB,
5647            0b00010 => DatType::InstructionTLB,
5648            0b00011 => DatType::UnifiedTLB,
5649            0b00000 => DatType::Null, // should never be returned as this indicates invalid struct!
5650            0b00100 => DatType::LoadOnly,
5651            0b00101 => DatType::StoreOnly,
5652            _ => DatType::Unknown,
5653        }
5654    }
5655
5656    /// Translation cache level (starts at 1)
5657    pub fn cache_level(&self) -> u8 {
5658        get_bits(self.edx, 5, 7) as u8
5659    }
5660
5661    /// Maximum number of addressable IDs for logical processors sharing this translation cache
5662    pub fn max_addressable_ids(&self) -> u16 {
5663        // Add one to the return value to get the result:
5664        (get_bits(self.edx, 14, 25) + 1) as u16
5665    }
5666}
5667
5668impl Debug for DatInfo {
5669    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
5670        f.debug_struct("DatInfo")
5671            .field("has_4k_entries", &self.has_4k_entries())
5672            .field("has_2mb_entries", &self.has_2mb_entries())
5673            .field("has_4mb_entries", &self.has_4mb_entries())
5674            .field("has_1gb_entries", &self.has_1gb_entries())
5675            .field("is_fully_associative", &self.is_fully_associative())
5676            .finish()
5677    }
5678}
5679
5680/// Deterministic Address Translation cache type (EDX bits 04 -- 00)
5681#[derive(Eq, PartialEq, Debug)]
5682pub enum DatType {
5683    /// Null (indicates this sub-leaf is not valid).
5684    Null = 0b00000,
5685    DataTLB = 0b00001,
5686    InstructionTLB = 0b00010,
5687    /// Some unified TLBs will allow a single TLB entry to satisfy data read/write
5688    /// and instruction fetches. Others will require separate entries (e.g., one
5689    /// loaded on data read/write and another loaded on an instruction fetch) .
5690    /// Please see the Intel® 64 and IA-32 Architectures Optimization Reference Manual
5691    /// for details of a particular product.
5692    UnifiedTLB = 0b00011,
5693    LoadOnly = 0b0100,
5694    StoreOnly = 0b0101,
5695    Unknown,
5696}
5697
5698impl fmt::Display for DatType {
5699    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
5700        let t = match self {
5701            DatType::Null => "invalid (0)",
5702            DatType::DataTLB => "Data TLB",
5703            DatType::InstructionTLB => "Instruction TLB",
5704            DatType::UnifiedTLB => "Unified TLB",
5705            DatType::LoadOnly => "Load Only",
5706            DatType::StoreOnly => "Store Only",
5707            DatType::Unknown => "Unknown",
5708        };
5709        f.write_str(t)
5710    }
5711}
5712
5713/// SoC vendor specific information (LEAF=0x17).
5714///
5715/// # Platforms
5716/// ❌ AMD ✅ Intel
5717pub struct SoCVendorInfo<R: CpuIdReader> {
5718    read: R,
5719    /// MaxSOCID_Index
5720    eax: u32,
5721    ebx: u32,
5722    ecx: u32,
5723    edx: u32,
5724}
5725
5726impl<R: CpuIdReader> SoCVendorInfo<R> {
5727    pub fn get_soc_vendor_id(&self) -> u16 {
5728        get_bits(self.ebx, 0, 15) as u16
5729    }
5730
5731    pub fn get_project_id(&self) -> u32 {
5732        self.ecx
5733    }
5734
5735    pub fn get_stepping_id(&self) -> u32 {
5736        self.edx
5737    }
5738
5739    pub fn get_vendor_brand(&self) -> Option<SoCVendorBrand> {
5740        // Leaf 17H is valid if MaxSOCID_Index >= 3.
5741        if self.eax >= 3 {
5742            let r1 = self.read.cpuid2(EAX_SOC_VENDOR_INFO, 1);
5743            let r2 = self.read.cpuid2(EAX_SOC_VENDOR_INFO, 2);
5744            let r3 = self.read.cpuid2(EAX_SOC_VENDOR_INFO, 3);
5745            Some(SoCVendorBrand { data: [r1, r2, r3] })
5746        } else {
5747            None
5748        }
5749    }
5750
5751    pub fn get_vendor_attributes(&self) -> Option<SoCVendorAttributesIter<R>> {
5752        if self.eax > 3 {
5753            Some(SoCVendorAttributesIter {
5754                read: self.read.clone(),
5755                count: self.eax,
5756                current: 3,
5757            })
5758        } else {
5759            None
5760        }
5761    }
5762}
5763
5764impl<R: CpuIdReader> fmt::Debug for SoCVendorInfo<R> {
5765    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
5766        f.debug_struct("SoCVendorInfo")
5767            .field("soc_vendor_id", &self.get_soc_vendor_id())
5768            .field("project_id", &self.get_project_id())
5769            .field("stepping_id", &self.get_stepping_id())
5770            .field("vendor_brand", &self.get_vendor_brand())
5771            .field("vendor_attributes", &self.get_vendor_attributes())
5772            .finish()
5773    }
5774}
5775
5776/// Iterator for SoC vendor attributes.
5777pub struct SoCVendorAttributesIter<R: CpuIdReader> {
5778    read: R,
5779    count: u32,
5780    current: u32,
5781}
5782
5783impl<R: CpuIdReader> fmt::Debug for SoCVendorAttributesIter<R> {
5784    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
5785        f.debug_struct("SocVendorAttributesIter")
5786            .field("count", &self.count)
5787            .field("current", &self.current)
5788            .finish()
5789    }
5790}
5791
5792impl<R: CpuIdReader> Iterator for SoCVendorAttributesIter<R> {
5793    type Item = CpuIdResult;
5794
5795    /// Iterate over all SoC vendor specific attributes.
5796    fn next(&mut self) -> Option<CpuIdResult> {
5797        if self.current > self.count {
5798            return None;
5799        }
5800        self.count += 1;
5801        Some(self.read.cpuid2(EAX_SOC_VENDOR_INFO, self.count))
5802    }
5803}
5804
5805/// A vendor brand string as queried from the cpuid leaf.
5806#[derive(Debug, PartialEq, Eq)]
5807#[repr(C)]
5808pub struct SoCVendorBrand {
5809    data: [CpuIdResult; 3],
5810}
5811
5812impl SoCVendorBrand {
5813    /// Return the SocVendorBrand as a string.
5814    pub fn as_str(&self) -> &str {
5815        let brand_string_start = self as *const SoCVendorBrand as *const u8;
5816        let slice = unsafe {
5817            // Safety: SoCVendorBrand is laid out with repr(C).
5818            slice::from_raw_parts(brand_string_start, size_of::<SoCVendorBrand>())
5819        };
5820        str::from_utf8(slice).unwrap_or("InvalidSoCVendorString")
5821    }
5822
5823    #[deprecated(
5824        since = "10.0.0",
5825        note = "Use idiomatic function name `as_str` instead"
5826    )]
5827    pub fn as_string(&self) -> &str {
5828        self.as_str()
5829    }
5830}
5831
5832impl fmt::Display for SoCVendorBrand {
5833    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
5834        write!(f, "{}", self.as_str())
5835    }
5836}
5837
5838/// Information about Hypervisor (LEAF=0x4000_0001)
5839///
5840/// More information about this semi-official leaf can be found here
5841/// <https://lwn.net/Articles/301888/>
5842pub struct HypervisorInfo<R: CpuIdReader> {
5843    read: R,
5844    res: CpuIdResult,
5845}
5846
5847impl<R: CpuIdReader> fmt::Debug for HypervisorInfo<R> {
5848    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
5849        f.debug_struct("HypervisorInfo")
5850            .field("identify", &self.identify())
5851            .field("tsc_frequency", &self.tsc_frequency())
5852            .field("apic_frequency", &self.apic_frequency())
5853            .finish()
5854    }
5855}
5856
5857/// Identifies the different Hypervisor products.
5858#[derive(Debug, Eq, PartialEq)]
5859pub enum Hypervisor {
5860    Xen,
5861    VMware,
5862    HyperV,
5863    KVM,
5864    /// QEMU is the hypervisor identity when QEMU is used
5865    /// without an accelerator, such as KVM.
5866    QEMU,
5867    Bhyve,
5868    QNX,
5869    ACRN,
5870    Unknown(u32, u32, u32),
5871}
5872
5873impl<R: CpuIdReader> HypervisorInfo<R> {
5874    /// Returns the identity of the [`Hypervisor`].
5875    ///
5876    /// ## Technical Background
5877    ///
5878    /// The value is a 12-byte (12 character) fixed-length ASCII string.
5879    ///
5880    /// Usually all of these IDs can be found in the original source code on
5881    /// Github relatively easy (if the project is open source). Once you
5882    /// have an ID, you find cumulated lists with all kinds of IDs on Github
5883    /// relatively easy.
5884    pub fn identify(&self) -> Hypervisor {
5885        match (self.res.ebx, self.res.ecx, self.res.edx) {
5886            // "VMwareVMware" (0x56 => V, 0x4d => M, ...)
5887            (0x61774d56, 0x4d566572, 0x65726177) => Hypervisor::VMware,
5888            // "XenVMMXenVMM"
5889            (0x566e6558, 0x65584d4d, 0x4d4d566e) => Hypervisor::Xen,
5890            // "Microsoft Hv"
5891            (0x7263694d, 0x666f736f, 0x76482074) => Hypervisor::HyperV,
5892            // "KVMKVMKVM\0\0\0"
5893            (0x4b4d564b, 0x564b4d56, 0x0000004d) => Hypervisor::KVM,
5894            // "TCGTCGTCGTCG"
5895            // see https://github.com/qemu/qemu/blob/6512fa497c2fa9751b9d774ab32d87a9764d1958/target/i386/cpu.c
5896            (0x54474354, 0x43544743, 0x47435447) => Hypervisor::QEMU,
5897            // "bhyve bhyve "
5898            // found this in another library ("heim-virt")
5899            (0x76796862, 0x68622065, 0x20657679) => Hypervisor::Bhyve,
5900            // "BHyVE BHyVE "
5901            // But this value is in the original source code. To be safe, we keep both.
5902            // See https://github.com/lattera/bhyve/blob/5946a9115d2771a1d27f14a835c7fbc05b30f7f9/sys/amd64/vmm/x86.c#L165
5903            (0x56794842, 0x48422045, 0x20455679) => Hypervisor::Bhyve,
5904            // "QNXQVMBSQG"
5905            // This can be verified in multiple Git repos (e.g. by Intel)
5906            // https://github.com/search?q=QNXQVMBSQG&type=code
5907            (0x51584e51, 0x53424d56, 0x00004751) => Hypervisor::QNX,
5908            // "ACRNACRNACRN"
5909            (0x4e524341, 0x4e524341, 0x4e524341) => Hypervisor::ACRN,
5910            (ebx, ecx, edx) => Hypervisor::Unknown(ebx, ecx, edx),
5911        }
5912    }
5913
5914    /// TSC frequency in kHz.
5915    pub fn tsc_frequency(&self) -> Option<u32> {
5916        // vm aware tsc frequency retrieval:
5917        // # EAX: (Virtual) TSC frequency in kHz.
5918        if self.res.eax >= 0x40000010 {
5919            let virt_tinfo = self.read.cpuid2(0x40000010, 0);
5920            Some(virt_tinfo.eax)
5921        } else {
5922            None
5923        }
5924    }
5925
5926    /// (Virtual) Bus (local apic timer) frequency in kHz.
5927    pub fn apic_frequency(&self) -> Option<u32> {
5928        // # EBX: (Virtual) Bus (local apic timer) frequency in kHz.
5929        if self.res.eax >= 0x40000010 {
5930            let virt_tinfo = self.read.cpuid2(0x40000010, 0);
5931            Some(virt_tinfo.ebx)
5932        } else {
5933            None
5934        }
5935    }
5936}
5937
5938#[cfg(doctest)]
5939mod test_readme {
5940    macro_rules! external_doc_test {
5941        ($x:expr) => {
5942            #[doc = $x]
5943            extern "C" {}
5944        };
5945    }
5946
5947    external_doc_test!(include_str!("../README.md"));
5948}