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 CET_SSS
3813    ///
3814    /// # Platforms
3815    /// ❌ AMD (reserved) ✅ Intel
3816    #[inline]
3817    pub const fn has_cet_sss(&self) -> bool {
3818        self.edx1.contains(ExtendedFeaturesEdx1::CET_SSS)
3819    }
3820}
3821
3822impl Debug for ExtendedFeatures {
3823    fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
3824        f.debug_struct("ExtendedFeatures")
3825            .field("ebx", &self.ebx)
3826            .field("ecx", &self.ecx)
3827            .field("mawau_value", &self.mawau_value())
3828            .finish()
3829    }
3830}
3831
3832bitflags! {
3833    #[repr(transparent)]
3834    #[derive(Debug, Clone, Copy, PartialEq, Eq)]
3835    struct ExtendedFeaturesEbx: u32 {
3836        /// FSGSBASE. Supports RDFSBASE/RDGSBASE/WRFSBASE/WRGSBASE if 1. (Bit 00)
3837        const FSGSBASE = 1 << 0;
3838        /// IA32_TSC_ADJUST MSR is supported if 1. (Bit 01)
3839        const ADJUST_MSR = 1 << 1;
3840        /// Bit 02: SGX. Supports Intel® Software Guard Extensions (Intel® SGX Extensions) if 1.
3841        const SGX = 1 << 2;
3842        /// BMI1 (Bit 03)
3843        const BMI1 = 1 << 3;
3844        /// HLE (Bit 04)
3845        const HLE = 1 << 4;
3846        /// AVX2 (Bit 05)
3847        const AVX2 = 1 << 5;
3848        /// FDP_EXCPTN_ONLY. x87 FPU Data Pointer updated only on x87 exceptions if 1.
3849        const FDP = 1 << 6;
3850        /// SMEP. Supports Supervisor-Mode Execution Prevention if 1. (Bit 07)
3851        const SMEP = 1 << 7;
3852        /// BMI2 (Bit 08)
3853        const BMI2 = 1 << 8;
3854        /// Supports Enhanced REP MOVSB/STOSB if 1. (Bit 09)
3855        const REP_MOVSB_STOSB = 1 << 9;
3856        /// INVPCID. If 1, supports INVPCID instruction for system software that manages process-context identifiers. (Bit 10)
3857        const INVPCID = 1 << 10;
3858        /// RTM (Bit 11)
3859        const RTM = 1 << 11;
3860        /// Supports Intel Resource Director Technology (RDT) Monitoring. (Bit 12)
3861        const RDTM = 1 << 12;
3862        /// Deprecates FPU CS and FPU DS values if 1. (Bit 13)
3863        const DEPRECATE_FPU_CS_DS = 1 << 13;
3864        /// Deprecates FPU CS and FPU DS values if 1. (Bit 14)
3865        const MPX = 1 << 14;
3866        /// Supports Intel Resource Director Technology (RDT) Allocation capability if 1.
3867        const RDTA = 1 << 15;
3868        /// Bit 16: AVX512F.
3869        const AVX512F = 1 << 16;
3870        /// Bit 17: AVX512DQ.
3871        const AVX512DQ = 1 << 17;
3872        /// Supports RDSEED.
3873        const RDSEED = 1 << 18;
3874        /// Supports ADX.
3875        const ADX = 1 << 19;
3876        /// SMAP. Supports Supervisor-Mode Access Prevention (and the CLAC/STAC instructions) if 1.
3877        const SMAP = 1 << 20;
3878        /// Bit 21: AVX512_IFMA.
3879        const AVX512_IFMA = 1 << 21;
3880        // Bit 22: Reserved.
3881        /// Bit 23: CLFLUSHOPT
3882        const CLFLUSHOPT = 1 << 23;
3883        /// Bit 24: CLWB.
3884        const CLWB = 1 << 24;
3885        /// Bit 25: Intel Processor Trace
3886        const PROCESSOR_TRACE = 1 << 25;
3887        /// Bit 26: AVX512PF. (Intel® Xeon Phi™ only.)
3888        const AVX512PF = 1 << 26;
3889        /// Bit 27: AVX512ER. (Intel® Xeon Phi™ only.)
3890        const AVX512ER = 1 << 27;
3891        /// Bit 28: AVX512CD.
3892        const AVX512CD = 1 << 28;
3893        /// Bit 29: Intel SHA Extensions
3894        const SHA = 1 << 29;
3895        /// Bit 30: AVX512BW.
3896        const AVX512BW = 1 << 30;
3897        /// Bit 31: AVX512VL.
3898        const AVX512VL = 1 << 31;
3899    }
3900}
3901
3902bitflags! {
3903    #[repr(transparent)]
3904    #[derive(Debug, Clone, Copy, PartialEq, Eq)]
3905    struct ExtendedFeaturesEcx: u32 {
3906        /// Bit 0: Prefetch WT1. (Intel® Xeon Phi™ only).
3907        const PREFETCHWT1 = 1 << 0;
3908        // Bit 01: AVX512_VBMI
3909        const AVX512VBMI = 1 << 1;
3910        /// Bit 02: UMIP. Supports user-mode instruction prevention if 1.
3911        const UMIP = 1 << 2;
3912        /// Bit 03: PKU. Supports protection keys for user-mode pages if 1.
3913        const PKU = 1 << 3;
3914        /// Bit 04: OSPKE. If 1, OS has set CR4.PKE to enable protection keys (and the RDPKRU/WRPKRU instruc-tions).
3915        const OSPKE = 1 << 4;
3916        /// Bit 5: WAITPKG
3917        const WAITPKG = 1 << 5;
3918        /// Bit 6: AV512_VBMI2
3919        const AVX512VBMI2 = 1 << 6;
3920        /// Bit 7: CET_SS. Supports CET shadow stack features if 1. Processors that set this bit define bits 0..2 of the
3921        /// IA32_U_CET and IA32_S_CET MSRs. Enumerates support for the following MSRs:
3922        /// IA32_INTERRUPT_SPP_TABLE_ADDR, IA32_PL3_SSP, IA32_PL2_SSP, IA32_PL1_SSP, and IA32_PL0_SSP.
3923        const CETSS = 1 << 7;
3924        /// Bit 8: GFNI
3925        const GFNI = 1 << 8;
3926        /// Bit 9: VAES
3927        const VAES = 1 << 9;
3928        /// Bit 10: VPCLMULQDQ
3929        const VPCLMULQDQ = 1 << 10;
3930        /// Bit 11: AVX512_VNNI
3931        const AVX512VNNI = 1 << 11;
3932        /// Bit 12: AVX512_BITALG
3933        const AVX512BITALG = 1 << 12;
3934        /// Bit 13: TME_EN. If 1, the following MSRs are supported: IA32_TME_CAPABILITY, IA32_TME_ACTIVATE,
3935        /// IA32_TME_EXCLUDE_MASK, and IA32_TME_EXCLUDE_BASE.
3936        const TMEEN = 1 << 13;
3937        /// Bit 14: AVX512_VPOPCNTDQ
3938        const AVX512VPOPCNTDQ = 1 << 14;
3939
3940        // Bit 15: Reserved.
3941
3942        /// Bit 16: Supports 57-bit linear addresses and five-level paging if 1.
3943        const LA57 = 1 << 16;
3944
3945        // Bits 21 - 17: The value of MAWAU used by the BNDLDX and BNDSTX instructions in 64-bit mode
3946
3947        /// Bit 22: RDPID. RDPID and IA32_TSC_AUX are available if 1.
3948        const RDPID = 1 << 22;
3949
3950        // Bits 29 - 23: Reserved.
3951
3952        /// Bit 30: SGX_LC. Supports SGX Launch Configuration if 1.
3953        const SGX_LC = 1 << 30;
3954    }
3955}
3956
3957bitflags! {
3958    #[repr(transparent)]
3959    #[derive(Debug, Clone, Copy, PartialEq, Eq)]
3960    struct ExtendedFeaturesEdx: u32 {
3961        /// Bit 02: AVX512_4VNNIW. (Intel® Xeon Phi™ only).
3962        const AVX512_4VNNIW = 1 << 2;
3963        /// Bit 03: AVX512_4FMAPS. (Intel® Xeon Phi™ only).
3964        const AVX512_4FMAPS = 1 << 3;
3965        /// Bit 08: AVX512_VP2INTERSECT.
3966        const AVX512_VP2INTERSECT = 1 << 8;
3967        /// Bit 22: AMX-BF16. If 1, the processor supports tile computational operations on bfloat16 numbers.
3968        const AMX_BF16 = 1 << 22;
3969        /// Bit 23: AVX512_FP16.
3970        const AVX512_FP16 = 1 << 23;
3971        /// Bit 24: AMX-TILE. If 1, the processor supports tile architecture
3972        const AMX_TILE = 1 << 24;
3973        /// Bit 25: AMX-INT8. If 1, the processor supports tile computational operations on 8-bit integers.
3974        const AMX_INT8 = 1 << 25;
3975    }
3976}
3977
3978bitflags! {
3979    #[repr(transparent)]
3980    #[derive(Debug, Clone, Copy, PartialEq, Eq)]
3981    struct ExtendedFeaturesEax1: u32 {
3982        // 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)
3983        /// Bit 04: AVX_VNNI. AVX (VEX-encoded) versions of the Vector Neural Network Instructions.
3984        const AVX_VNNI = 1 << 4;
3985        /// Bit 05: AVX512_BF16. Vector Neural Network Instructions supporting BFLOAT16 inputs and conversion instructions from IEEE single precision.
3986        const AVX512_BF16 = 1 << 5;
3987        /// Bit 10: If 1, supports fast zero-length REP MOVSB.
3988        const FZRM = 1 << 10;
3989        /// Bit 11: If 1, supports fast short REP STOSB.
3990        const FSRS = 1 << 11;
3991        /// Bit 12: If 1, supports fast short REP CMPSB, REP SCASB.
3992        const FSRCRS = 1 << 12;
3993        /// 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.
3994        const HRESET = 1 << 22;
3995    }
3996}
3997
3998bitflags! {
3999    #[repr(transparent)]
4000    #[derive(Debug, Clone, Copy, PartialEq, Eq)]
4001    struct ExtendedFeaturesEdx1: u32 {
4002        // 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)
4003        /// 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
4004        const CET_SSS = 1 << 18;
4005    }
4006}
4007
4008/// Direct cache access info (LEAF=0x09).
4009///
4010/// # Platforms
4011/// ❌ AMD (reserved) ✅ Intel
4012pub struct DirectCacheAccessInfo {
4013    eax: u32,
4014}
4015
4016impl DirectCacheAccessInfo {
4017    /// Value of bits \[31:0\] of IA32_PLATFORM_DCA_CAP MSR (address 1F8H)
4018    pub fn get_dca_cap_value(&self) -> u32 {
4019        self.eax
4020    }
4021}
4022
4023impl Debug for DirectCacheAccessInfo {
4024    fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
4025        f.debug_struct("DirectCacheAccessInfo")
4026            .field("dca_cap_value", &self.get_dca_cap_value())
4027            .finish()
4028    }
4029}
4030
4031/// Info about performance monitoring -- how many counters etc. (LEAF=0x0A)
4032///
4033/// # Platforms
4034/// ❌ AMD ✅ Intel
4035pub struct PerformanceMonitoringInfo {
4036    eax: u32,
4037    ebx: PerformanceMonitoringFeaturesEbx,
4038    _ecx: u32,
4039    edx: u32,
4040}
4041
4042impl PerformanceMonitoringInfo {
4043    /// Version ID of architectural performance monitoring. (Bits 07 - 00)
4044    pub fn version_id(&self) -> u8 {
4045        get_bits(self.eax, 0, 7) as u8
4046    }
4047
4048    /// Number of general-purpose performance monitoring counter per logical processor. (Bits 15- 08)
4049    pub fn number_of_counters(&self) -> u8 {
4050        get_bits(self.eax, 8, 15) as u8
4051    }
4052
4053    /// Bit width of general-purpose, performance monitoring counter. (Bits 23 - 16)
4054    pub fn counter_bit_width(&self) -> u8 {
4055        get_bits(self.eax, 16, 23) as u8
4056    }
4057
4058    /// Length of EBX bit vector to enumerate architectural performance monitoring events. (Bits 31 - 24)
4059    pub fn ebx_length(&self) -> u8 {
4060        get_bits(self.eax, 24, 31) as u8
4061    }
4062
4063    /// Number of fixed-function performance counters (if Version ID > 1). (Bits 04 - 00)
4064    pub fn fixed_function_counters(&self) -> u8 {
4065        get_bits(self.edx, 0, 4) as u8
4066    }
4067
4068    /// Bit width of fixed-function performance counters (if Version ID > 1). (Bits 12- 05)
4069    pub fn fixed_function_counters_bit_width(&self) -> u8 {
4070        get_bits(self.edx, 5, 12) as u8
4071    }
4072
4073    check_bit_fn!(
4074        doc = "AnyThread deprecation",
4075        has_any_thread_deprecation,
4076        edx,
4077        15
4078    );
4079
4080    check_flag!(
4081        doc = "Core cycle event not available if 1.",
4082        is_core_cyc_ev_unavailable,
4083        ebx,
4084        PerformanceMonitoringFeaturesEbx::CORE_CYC_EV_UNAVAILABLE
4085    );
4086
4087    check_flag!(
4088        doc = "Instruction retired event not available if 1.",
4089        is_inst_ret_ev_unavailable,
4090        ebx,
4091        PerformanceMonitoringFeaturesEbx::INST_RET_EV_UNAVAILABLE
4092    );
4093
4094    check_flag!(
4095        doc = "Reference cycles event not available if 1.",
4096        is_ref_cycle_ev_unavailable,
4097        ebx,
4098        PerformanceMonitoringFeaturesEbx::REF_CYC_EV_UNAVAILABLE
4099    );
4100
4101    check_flag!(
4102        doc = "Last-level cache reference event not available if 1.",
4103        is_cache_ref_ev_unavailable,
4104        ebx,
4105        PerformanceMonitoringFeaturesEbx::CACHE_REF_EV_UNAVAILABLE
4106    );
4107
4108    check_flag!(
4109        doc = "Last-level cache misses event not available if 1.",
4110        is_ll_cache_miss_ev_unavailable,
4111        ebx,
4112        PerformanceMonitoringFeaturesEbx::LL_CACHE_MISS_EV_UNAVAILABLE
4113    );
4114
4115    check_flag!(
4116        doc = "Branch instruction retired event not available if 1.",
4117        is_branch_inst_ret_ev_unavailable,
4118        ebx,
4119        PerformanceMonitoringFeaturesEbx::BRANCH_INST_RET_EV_UNAVAILABLE
4120    );
4121
4122    check_flag!(
4123        doc = "Branch mispredict retired event not available if 1.",
4124        is_branch_midpred_ev_unavailable,
4125        ebx,
4126        PerformanceMonitoringFeaturesEbx::BRANCH_MISPRED_EV_UNAVAILABLE
4127    );
4128}
4129
4130impl Debug for PerformanceMonitoringInfo {
4131    fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
4132        f.debug_struct("PerformanceMonitoringInfo")
4133            .field("version_id", &self.version_id())
4134            .field("number_of_counters", &self.number_of_counters())
4135            .field("counter_bit_width", &self.counter_bit_width())
4136            .field("ebx_length", &self.ebx_length())
4137            .field("fixed_function_counters", &self.fixed_function_counters())
4138            .field(
4139                "fixed_function_counters_bit_width",
4140                &self.fixed_function_counters_bit_width(),
4141            )
4142            .finish()
4143    }
4144}
4145
4146bitflags! {
4147    #[repr(transparent)]
4148    #[derive(Debug, Clone, Copy, PartialEq, Eq)]
4149    struct PerformanceMonitoringFeaturesEbx: u32 {
4150        /// Core cycle event not available if 1. (Bit 0)
4151        const CORE_CYC_EV_UNAVAILABLE = 1 << 0;
4152        /// Instruction retired event not available if 1. (Bit 01)
4153        const INST_RET_EV_UNAVAILABLE = 1 << 1;
4154        /// Reference cycles event not available if 1. (Bit 02)
4155        const REF_CYC_EV_UNAVAILABLE = 1 << 2;
4156        /// Last-level cache reference event not available if 1. (Bit 03)
4157        const CACHE_REF_EV_UNAVAILABLE = 1 << 3;
4158        /// Last-level cache misses event not available if 1. (Bit 04)
4159        const LL_CACHE_MISS_EV_UNAVAILABLE = 1 << 4;
4160        /// Branch instruction retired event not available if 1. (Bit 05)
4161        const BRANCH_INST_RET_EV_UNAVAILABLE = 1 << 5;
4162        /// Branch mispredict retired event not available if 1. (Bit 06)
4163        const BRANCH_MISPRED_EV_UNAVAILABLE = 1 << 6;
4164    }
4165}
4166
4167/// Information about topology (LEAF=0x0B).
4168///
4169/// Iterates over the system topology in order to retrieve more system
4170/// information at each level of the topology: how many cores and what kind of
4171/// cores
4172///
4173/// # Platforms
4174/// ✅ AMD ✅ Intel
4175#[derive(Clone)]
4176pub struct ExtendedTopologyIter<R: CpuIdReader> {
4177    read: R,
4178    level: u32,
4179    is_v2: bool,
4180}
4181
4182/// Gives information about the current level in the topology.
4183///
4184/// How many cores, what type etc.
4185#[derive(PartialEq, Eq)]
4186pub struct ExtendedTopologyLevel {
4187    eax: u32,
4188    ebx: u32,
4189    ecx: u32,
4190    edx: u32,
4191}
4192
4193impl fmt::Debug for ExtendedTopologyLevel {
4194    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
4195        f.debug_struct("ExtendedTopologyLevel")
4196            .field("processors", &self.processors())
4197            .field("number", &self.level_number())
4198            .field("type", &self.level_type())
4199            .field("x2apic_id", &self.x2apic_id())
4200            .field("next_apic_id", &self.shift_right_for_next_apic_id())
4201            .finish()
4202    }
4203}
4204
4205impl ExtendedTopologyLevel {
4206    /// Number of logical processors at this level type.
4207    /// The number reflects configuration as shipped.
4208    pub fn processors(&self) -> u16 {
4209        get_bits(self.ebx, 0, 15) as u16
4210    }
4211
4212    /// Level number.
4213    pub fn level_number(&self) -> u8 {
4214        get_bits(self.ecx, 0, 7) as u8
4215    }
4216
4217    // Level type.
4218    pub fn level_type(&self) -> TopologyType {
4219        match get_bits(self.ecx, 8, 15) {
4220            0 => TopologyType::Invalid,
4221            1 => TopologyType::SMT,
4222            2 => TopologyType::Core,
4223            3 => TopologyType::Module,
4224            4 => TopologyType::Tile,
4225            5 => TopologyType::Die,
4226            _ => unreachable!(),
4227        }
4228    }
4229
4230    /// x2APIC ID the current logical processor. (Bits 31-00)
4231    pub fn x2apic_id(&self) -> u32 {
4232        self.edx
4233    }
4234
4235    /// Number of bits to shift right on x2APIC ID to get a unique topology ID of the next level type. (Bits 04-00)
4236    /// All logical processors with the same next level ID share current level.
4237    pub fn shift_right_for_next_apic_id(&self) -> u32 {
4238        get_bits(self.eax, 0, 4)
4239    }
4240}
4241
4242/// What type of core we have at this level in the topology (real CPU or hyper-threaded).
4243#[derive(PartialEq, Eq, Debug)]
4244pub enum TopologyType {
4245    Invalid = 0,
4246    /// Hyper-thread (Simultaneous multithreading)
4247    SMT = 1,
4248    Core = 2,
4249    Module = 3,
4250    Tile = 4,
4251    Die = 5,
4252}
4253
4254impl fmt::Display for TopologyType {
4255    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
4256        let data = match self {
4257            TopologyType::Invalid => "Invalid",
4258            TopologyType::SMT => "SMT",
4259            TopologyType::Core => "Core",
4260            TopologyType::Module => "Module",
4261            TopologyType::Tile => "Tile",
4262            TopologyType::Die => "Die",
4263        };
4264
4265        f.write_str(data)
4266    }
4267}
4268
4269impl<R: CpuIdReader> Iterator for ExtendedTopologyIter<R> {
4270    type Item = ExtendedTopologyLevel;
4271
4272    fn next(&mut self) -> Option<ExtendedTopologyLevel> {
4273        let res = if self.is_v2 {
4274            self.read.cpuid2(EAX_EXTENDED_TOPOLOGY_INFO_V2, self.level)
4275        } else {
4276            self.read.cpuid2(EAX_EXTENDED_TOPOLOGY_INFO, self.level)
4277        };
4278        self.level += 1;
4279
4280        let et = ExtendedTopologyLevel {
4281            eax: res.eax,
4282            ebx: res.ebx,
4283            ecx: res.ecx,
4284            edx: res.edx,
4285        };
4286
4287        match et.level_type() {
4288            TopologyType::Invalid => None,
4289            _ => Some(et),
4290        }
4291    }
4292}
4293
4294impl<R: CpuIdReader> Debug for ExtendedTopologyIter<R> {
4295    fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
4296        let mut debug = f.debug_list();
4297        self.clone().for_each(|ref item| {
4298            debug.entry(item);
4299        });
4300        debug.finish()
4301    }
4302}
4303
4304bitflags! {
4305    #[repr(transparent)]
4306    #[derive(Debug, Clone, Copy, PartialEq, Eq)]
4307    struct ExtendedStateInfoXCR0Flags: u32 {
4308        /// legacy x87 (Bit 00).
4309        const LEGACY_X87 = 1 << 0;
4310
4311        /// 128-bit SSE (Bit 01).
4312        const SSE128 = 1 << 1;
4313
4314        /// 256-bit AVX (Bit 02).
4315        const AVX256 = 1 << 2;
4316
4317        /// MPX BNDREGS (Bit 03).
4318        const MPX_BNDREGS = 1 << 3;
4319
4320        /// MPX BNDCSR (Bit 04).
4321        const MPX_BNDCSR = 1 << 4;
4322
4323        /// AVX512 OPMASK (Bit 05).
4324        const AVX512_OPMASK = 1 << 5;
4325
4326        /// AVX ZMM Hi256 (Bit 06).
4327        const AVX512_ZMM_HI256 = 1 << 6;
4328
4329        /// AVX 512 ZMM Hi16 (Bit 07).
4330        const AVX512_ZMM_HI16 = 1 << 7;
4331
4332        /// PKRU state (Bit 09).
4333        const PKRU = 1 << 9;
4334
4335        /// IA32_XSS HDC State (Bit 13).
4336        const IA32_XSS_HDC = 1 << 13;
4337
4338        /// AMX TILECFG state (Bit 17)
4339        const AMX_TILECFG = 1 << 17;
4340
4341        /// AMX TILEDATA state (Bit 17)
4342        const AMX_TILEDATA = 1 << 18;
4343    }
4344}
4345
4346bitflags! {
4347    #[repr(transparent)]
4348    #[derive(Debug, Clone, Copy, PartialEq, Eq)]
4349    struct ExtendedStateInfoXSSFlags: u32 {
4350        /// IA32_XSS PT (Trace Packet) State (Bit 08).
4351        const PT = 1 << 8;
4352
4353        /// IA32_XSS PASID state (Bit 10)
4354        const PASID = 1 << 10;
4355
4356        /// IA32_XSS CET user state (Bit 11)
4357        const CET_USER = 1 << 11;
4358
4359        /// IA32_XSS CET supervisor state (Bit 12)
4360        const CET_SUPERVISOR = 1 << 12;
4361
4362        /// IA32_XSS HDC State (Bit 13).
4363        const HDC = 1 << 13;
4364
4365        /// IA32_XSS UINTR state (Bit 14)
4366        const UINTR = 1 << 14;
4367
4368        /// IA32_XSS LBR state (Bit 15)
4369        const LBR = 1 << 15;
4370
4371        /// IA32_XSS HWP state (Bit 16)
4372        const HWP = 1 << 16;
4373    }
4374}
4375
4376/// Information for saving/restoring extended register state (LEAF=0x0D).
4377///
4378/// # Platforms
4379/// ✅ AMD ✅ Intel
4380pub struct ExtendedStateInfo<R: CpuIdReader> {
4381    read: R,
4382    eax: ExtendedStateInfoXCR0Flags,
4383    ebx: u32,
4384    ecx: u32,
4385    _edx: u32,
4386    eax1: u32,
4387    ebx1: u32,
4388    ecx1: ExtendedStateInfoXSSFlags,
4389    _edx1: u32,
4390}
4391
4392impl<F: CpuIdReader> ExtendedStateInfo<F> {
4393    check_flag!(
4394        doc = "Support for legacy x87 in XCR0.",
4395        xcr0_supports_legacy_x87,
4396        eax,
4397        ExtendedStateInfoXCR0Flags::LEGACY_X87
4398    );
4399
4400    check_flag!(
4401        doc = "Support for SSE 128-bit in XCR0.",
4402        xcr0_supports_sse_128,
4403        eax,
4404        ExtendedStateInfoXCR0Flags::SSE128
4405    );
4406
4407    check_flag!(
4408        doc = "Support for AVX 256-bit in XCR0.",
4409        xcr0_supports_avx_256,
4410        eax,
4411        ExtendedStateInfoXCR0Flags::AVX256
4412    );
4413
4414    check_flag!(
4415        doc = "Support for MPX BNDREGS in XCR0.",
4416        xcr0_supports_mpx_bndregs,
4417        eax,
4418        ExtendedStateInfoXCR0Flags::MPX_BNDREGS
4419    );
4420
4421    check_flag!(
4422        doc = "Support for MPX BNDCSR in XCR0.",
4423        xcr0_supports_mpx_bndcsr,
4424        eax,
4425        ExtendedStateInfoXCR0Flags::MPX_BNDCSR
4426    );
4427
4428    check_flag!(
4429        doc = "Support for AVX512 OPMASK in XCR0.",
4430        xcr0_supports_avx512_opmask,
4431        eax,
4432        ExtendedStateInfoXCR0Flags::AVX512_OPMASK
4433    );
4434
4435    check_flag!(
4436        doc = "Support for AVX512 ZMM Hi256 XCR0.",
4437        xcr0_supports_avx512_zmm_hi256,
4438        eax,
4439        ExtendedStateInfoXCR0Flags::AVX512_ZMM_HI256
4440    );
4441
4442    check_flag!(
4443        doc = "Support for AVX512 ZMM Hi16 in XCR0.",
4444        xcr0_supports_avx512_zmm_hi16,
4445        eax,
4446        ExtendedStateInfoXCR0Flags::AVX512_ZMM_HI16
4447    );
4448
4449    check_flag!(
4450        doc = "Support for PKRU in XCR0.",
4451        xcr0_supports_pkru,
4452        eax,
4453        ExtendedStateInfoXCR0Flags::PKRU
4454    );
4455
4456    check_flag!(
4457        doc = "Support for PT in IA32_XSS.",
4458        ia32_xss_supports_pt,
4459        ecx1,
4460        ExtendedStateInfoXSSFlags::PT
4461    );
4462
4463    check_flag!(
4464        doc = "Support for HDC in IA32_XSS.",
4465        ia32_xss_supports_hdc,
4466        ecx1,
4467        ExtendedStateInfoXSSFlags::HDC
4468    );
4469
4470    /// Maximum size (bytes, from the beginning of the XSAVE/XRSTOR save area) required by
4471    /// enabled features in XCR0. May be different than ECX if some features at the end of the XSAVE save area
4472    /// are not enabled.
4473    pub fn xsave_area_size_enabled_features(&self) -> u32 {
4474        self.ebx
4475    }
4476
4477    /// Maximum size (bytes, from the beginning of the XSAVE/XRSTOR save area) of the
4478    /// XSAVE/XRSTOR save area required by all supported features in the processor,
4479    /// i.e all the valid bit fields in XCR0.
4480    pub fn xsave_area_size_supported_features(&self) -> u32 {
4481        self.ecx
4482    }
4483
4484    /// CPU has xsaveopt feature.
4485    pub fn has_xsaveopt(&self) -> bool {
4486        self.eax1 & 0x1 > 0
4487    }
4488
4489    /// Supports XSAVEC and the compacted form of XRSTOR if set.
4490    pub fn has_xsavec(&self) -> bool {
4491        self.eax1 & 0b10 > 0
4492    }
4493
4494    /// Supports XGETBV with ECX = 1 if set.
4495    pub fn has_xgetbv(&self) -> bool {
4496        self.eax1 & 0b100 > 0
4497    }
4498
4499    /// Supports XSAVES/XRSTORS and IA32_XSS if set.
4500    pub fn has_xsaves_xrstors(&self) -> bool {
4501        self.eax1 & 0b1000 > 0
4502    }
4503
4504    /// The size in bytes of the XSAVE area containing all states enabled by XCRO | IA32_XSS.
4505    pub fn xsave_size(&self) -> u32 {
4506        self.ebx1
4507    }
4508
4509    /// Iterator over extended state enumeration levels >= 2.
4510    pub fn iter(&self) -> ExtendedStateIter<F> {
4511        ExtendedStateIter {
4512            read: self.read.clone(),
4513            level: 1,
4514            supported_xcr0: self.eax.bits(),
4515            supported_xss: self.ecx1.bits(),
4516        }
4517    }
4518}
4519
4520impl<R: CpuIdReader> Debug for ExtendedStateInfo<R> {
4521    fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
4522        f.debug_struct("ExtendedStateInfo")
4523            .field("eax", &self.eax)
4524            .field("ecx1", &self.ecx1)
4525            .field(
4526                "xsave_area_size_enabled_features",
4527                &self.xsave_area_size_enabled_features(),
4528            )
4529            .field(
4530                "xsave_area_size_supported_features",
4531                &self.xsave_area_size_supported_features(),
4532            )
4533            .field("has_xsaveopt", &self.has_xsaveopt())
4534            .field("has_xsavec", &self.has_xsavec())
4535            .field("has_xgetbv", &self.has_xgetbv())
4536            .field("has_xsaves_xrstors", &self.has_xsaves_xrstors())
4537            .field("xsave_size", &self.xsave_size())
4538            .field("extended_state_iter", &self.iter())
4539            .finish()
4540    }
4541}
4542
4543/// Yields [ExtendedState] structs.
4544#[derive(Clone)]
4545pub struct ExtendedStateIter<R: CpuIdReader> {
4546    read: R,
4547    level: u32,
4548    supported_xcr0: u32,
4549    supported_xss: u32,
4550}
4551
4552/// When CPUID executes with EAX set to 0DH and ECX = n (n > 1, and is a valid
4553/// sub-leaf index), the processor returns information about the size and offset
4554/// of each processor extended state save area within the XSAVE/XRSTOR area.
4555///
4556/// The iterator goes over the valid sub-leaves and obtain size and offset
4557/// information for each processor extended state save area:
4558impl<R: CpuIdReader> Iterator for ExtendedStateIter<R> {
4559    type Item = ExtendedState;
4560
4561    fn next(&mut self) -> Option<ExtendedState> {
4562        self.level += 1;
4563        if self.level > 31 {
4564            return None;
4565        }
4566
4567        let bit = 1 << self.level;
4568        if (self.supported_xcr0 & bit > 0) || (self.supported_xss & bit > 0) {
4569            let res = self.read.cpuid2(EAX_EXTENDED_STATE_INFO, self.level);
4570            return Some(ExtendedState {
4571                subleaf: self.level,
4572                eax: res.eax,
4573                ebx: res.ebx,
4574                ecx: res.ecx,
4575            });
4576        }
4577
4578        self.next()
4579    }
4580}
4581
4582impl<R: CpuIdReader> Debug for ExtendedStateIter<R> {
4583    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
4584        let mut debug = f.debug_list();
4585        self.clone().for_each(|ref item| {
4586            debug.entry(item);
4587        });
4588        debug.finish()
4589    }
4590}
4591
4592/// What kidn of extended register state this is.
4593#[derive(PartialEq, Eq, Debug)]
4594#[repr(u32)]
4595pub enum ExtendedRegisterType {
4596    Avx,
4597    MpxBndregs,
4598    MpxBndcsr,
4599    Avx512Opmask,
4600    Avx512ZmmHi256,
4601    Avx512ZmmHi16,
4602    Pt,
4603    Pkru,
4604    Hdc,
4605    Unknown(u32),
4606}
4607
4608impl From<u32> for ExtendedRegisterType {
4609    fn from(value: u32) -> ExtendedRegisterType {
4610        match value {
4611            0x2 => ExtendedRegisterType::Avx,
4612            0x3 => ExtendedRegisterType::MpxBndregs,
4613            0x4 => ExtendedRegisterType::MpxBndcsr,
4614            0x5 => ExtendedRegisterType::Avx512Opmask,
4615            0x6 => ExtendedRegisterType::Avx512ZmmHi256,
4616            0x7 => ExtendedRegisterType::Avx512ZmmHi16,
4617            0x8 => ExtendedRegisterType::Pt,
4618            0x9 => ExtendedRegisterType::Pkru,
4619            0xd => ExtendedRegisterType::Hdc,
4620            x => ExtendedRegisterType::Unknown(x),
4621        }
4622    }
4623}
4624
4625impl fmt::Display for ExtendedRegisterType {
4626    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
4627        let data = match self {
4628            ExtendedRegisterType::Avx => "AVX/YMM",
4629            ExtendedRegisterType::MpxBndregs => "MPX BNDREGS",
4630            ExtendedRegisterType::MpxBndcsr => "MPX BNDCSR",
4631            ExtendedRegisterType::Avx512Opmask => "AVX-512 opmask",
4632            ExtendedRegisterType::Avx512ZmmHi256 => "AVX-512 ZMM_Hi256",
4633            ExtendedRegisterType::Avx512ZmmHi16 => "AVX-512 Hi16_ZMM",
4634            ExtendedRegisterType::Pkru => "PKRU",
4635            ExtendedRegisterType::Pt => "PT",
4636            ExtendedRegisterType::Hdc => "HDC",
4637            ExtendedRegisterType::Unknown(t) => {
4638                return write!(f, "Unknown({})", t);
4639            }
4640        };
4641
4642        f.write_str(data)
4643    }
4644}
4645
4646/// Where the extended register state is stored.
4647#[derive(PartialEq, Eq, Debug)]
4648pub enum ExtendedRegisterStateLocation {
4649    Xcr0,
4650    Ia32Xss,
4651}
4652
4653impl fmt::Display for ExtendedRegisterStateLocation {
4654    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
4655        let data = match self {
4656            ExtendedRegisterStateLocation::Xcr0 => "XCR0 (user state)",
4657            ExtendedRegisterStateLocation::Ia32Xss => "IA32_XSS (supervisor state)",
4658        };
4659
4660        f.write_str(data)
4661    }
4662}
4663
4664/// ExtendedState subleaf structure for things that need to be restored.
4665pub struct ExtendedState {
4666    pub subleaf: u32,
4667    eax: u32,
4668    ebx: u32,
4669    ecx: u32,
4670}
4671
4672impl ExtendedState {
4673    /// Returns which register this specific extended subleaf contains information for.
4674    pub fn register(&self) -> ExtendedRegisterType {
4675        self.subleaf.into()
4676    }
4677
4678    /// The size in bytes (from the offset specified in EBX) of the save area
4679    /// for an extended state feature associated with a valid sub-leaf index, n.
4680    /// This field reports 0 if the sub-leaf index, n, is invalid.
4681    pub fn size(&self) -> u32 {
4682        self.eax
4683    }
4684
4685    /// The offset in bytes of this extended state components save area
4686    /// from the beginning of the XSAVE/XRSTOR area.
4687    pub fn offset(&self) -> u32 {
4688        self.ebx
4689    }
4690
4691    pub fn location(&self) -> ExtendedRegisterStateLocation {
4692        if self.is_in_xcr0() {
4693            ExtendedRegisterStateLocation::Xcr0
4694        } else {
4695            ExtendedRegisterStateLocation::Ia32Xss
4696        }
4697    }
4698
4699    /// True if the bit n (corresponding to the sub-leaf index)
4700    /// is supported in the IA32_XSS MSR;
4701    ///
4702    /// # Deprecation note
4703    /// This will likely be removed in the future. Use `location()` instead.
4704    pub fn is_in_ia32_xss(&self) -> bool {
4705        self.ecx & 0b1 > 0
4706    }
4707
4708    /// True if bit n is supported in XCR0.
4709    ///
4710    /// # Deprecation note
4711    /// This will likely be removed in the future. Use `location()` instead.
4712    pub fn is_in_xcr0(&self) -> bool {
4713        self.ecx & 0b1 == 0
4714    }
4715
4716    /// Returns true when the compacted format of an XSAVE area is used,
4717    /// this extended state component located on the next 64-byte
4718    /// boundary following the preceding state component
4719    /// (otherwise, it is located immediately following the preceding state component).
4720    pub fn is_compacted_format(&self) -> bool {
4721        self.ecx & 0b10 > 0
4722    }
4723}
4724
4725impl Debug for ExtendedState {
4726    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
4727        f.debug_struct("ExtendedState")
4728            .field("size", &self.size())
4729            .field("offset", &self.offset())
4730            .field("is_in_ia32_xss", &self.is_in_ia32_xss())
4731            .field("is_in_xcr0", &self.is_in_xcr0())
4732            .field("is_compacted_format", &self.is_compacted_format())
4733            .finish()
4734    }
4735}
4736
4737/// Intel Resource Director Technology RDT (LEAF=0x0F).
4738///
4739/// Monitoring Enumeration Sub-leaf (EAX = 0FH, ECX = 0 and ECX = 1)
4740/// # Platforms
4741/// ❌ AMD ✅ Intel
4742pub struct RdtMonitoringInfo<R: CpuIdReader> {
4743    read: R,
4744    ebx: u32,
4745    edx: u32,
4746}
4747
4748impl<R: CpuIdReader> RdtMonitoringInfo<R> {
4749    /// Maximum range (zero-based) of RMID within this physical processor of all types.
4750    pub fn rmid_range(&self) -> u32 {
4751        self.ebx
4752    }
4753
4754    check_bit_fn!(
4755        doc = "Supports L3 Cache Intel RDT Monitoring.",
4756        has_l3_monitoring,
4757        edx,
4758        1
4759    );
4760
4761    /// L3 Cache Monitoring.
4762    pub fn l3_monitoring(&self) -> Option<L3MonitoringInfo> {
4763        if self.has_l3_monitoring() {
4764            let res = self.read.cpuid2(EAX_RDT_MONITORING, 1);
4765            Some(L3MonitoringInfo {
4766                ebx: res.ebx,
4767                ecx: res.ecx,
4768                edx: res.edx,
4769            })
4770        } else {
4771            None
4772        }
4773    }
4774}
4775
4776impl<R: CpuIdReader> Debug for RdtMonitoringInfo<R> {
4777    fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
4778        f.debug_struct("RdtMonitoringInfo")
4779            .field("rmid_range", &self.rmid_range())
4780            .field("l3_monitoring", &self.l3_monitoring())
4781            .finish()
4782    }
4783}
4784
4785/// Information about L3 cache monitoring.
4786pub struct L3MonitoringInfo {
4787    ebx: u32,
4788    ecx: u32,
4789    edx: u32,
4790}
4791
4792impl L3MonitoringInfo {
4793    /// Conversion factor from reported IA32_QM_CTR value to occupancy metric (bytes).
4794    pub fn conversion_factor(&self) -> u32 {
4795        self.ebx
4796    }
4797
4798    /// Maximum range (zero-based) of RMID of L3.
4799    pub fn maximum_rmid_range(&self) -> u32 {
4800        self.ecx
4801    }
4802
4803    check_bit_fn!(
4804        doc = "Supports occupancy monitoring.",
4805        has_occupancy_monitoring,
4806        edx,
4807        0
4808    );
4809
4810    check_bit_fn!(
4811        doc = "Supports total bandwidth monitoring.",
4812        has_total_bandwidth_monitoring,
4813        edx,
4814        1
4815    );
4816
4817    check_bit_fn!(
4818        doc = "Supports local bandwidth monitoring.",
4819        has_local_bandwidth_monitoring,
4820        edx,
4821        2
4822    );
4823}
4824
4825impl Debug for L3MonitoringInfo {
4826    fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
4827        f.debug_struct("L3MonitoringInfo")
4828            .field("conversion_factor", &self.conversion_factor())
4829            .field("maximum_rmid_range", &self.maximum_rmid_range())
4830            .finish()
4831    }
4832}
4833
4834/// Quality of service enforcement information (LEAF=0x10).
4835///
4836/// # Platforms
4837/// ❌ AMD ✅ Intel
4838pub struct RdtAllocationInfo<R: CpuIdReader> {
4839    read: R,
4840    ebx: u32,
4841}
4842
4843impl<R: CpuIdReader> RdtAllocationInfo<R> {
4844    check_bit_fn!(doc = "Supports L3 Cache Allocation.", has_l3_cat, ebx, 1);
4845
4846    check_bit_fn!(doc = "Supports L2 Cache Allocation.", has_l2_cat, ebx, 2);
4847
4848    check_bit_fn!(
4849        doc = "Supports Memory Bandwidth Allocation.",
4850        has_memory_bandwidth_allocation,
4851        ebx,
4852        3
4853    );
4854
4855    /// L3 Cache Allocation Information.
4856    pub fn l3_cat(&self) -> Option<L3CatInfo> {
4857        if self.has_l3_cat() {
4858            let res = self.read.cpuid2(EAX_RDT_ALLOCATION, 1);
4859            Some(L3CatInfo {
4860                eax: res.eax,
4861                ebx: res.ebx,
4862                ecx: res.ecx,
4863                edx: res.edx,
4864            })
4865        } else {
4866            None
4867        }
4868    }
4869
4870    /// L2 Cache Allocation Information.
4871    pub fn l2_cat(&self) -> Option<L2CatInfo> {
4872        if self.has_l2_cat() {
4873            let res = self.read.cpuid2(EAX_RDT_ALLOCATION, 2);
4874            Some(L2CatInfo {
4875                eax: res.eax,
4876                ebx: res.ebx,
4877                edx: res.edx,
4878            })
4879        } else {
4880            None
4881        }
4882    }
4883
4884    /// Memory Bandwidth Allocation Information.
4885    pub fn memory_bandwidth_allocation(&self) -> Option<MemBwAllocationInfo> {
4886        if self.has_memory_bandwidth_allocation() {
4887            let res = self.read.cpuid2(EAX_RDT_ALLOCATION, 3);
4888            Some(MemBwAllocationInfo {
4889                eax: res.eax,
4890                ecx: res.ecx,
4891                edx: res.edx,
4892            })
4893        } else {
4894            None
4895        }
4896    }
4897}
4898
4899impl<R: CpuIdReader> Debug for RdtAllocationInfo<R> {
4900    fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
4901        f.debug_struct("RdtAllocationInfo")
4902            .field("l3_cat", &self.l3_cat())
4903            .field("l2_cat", &self.l2_cat())
4904            .field(
4905                "memory_bandwidth_allocation",
4906                &self.memory_bandwidth_allocation(),
4907            )
4908            .finish()
4909    }
4910}
4911
4912/// L3 Cache Allocation Technology Enumeration Sub-leaf (LEAF=0x10, SUBLEAF=1).
4913pub struct L3CatInfo {
4914    eax: u32,
4915    ebx: u32,
4916    ecx: u32,
4917    edx: u32,
4918}
4919
4920impl L3CatInfo {
4921    /// Length of the capacity bit mask.
4922    pub fn capacity_mask_length(&self) -> u8 {
4923        (get_bits(self.eax, 0, 4) + 1) as u8
4924    }
4925
4926    /// Bit-granular map of isolation/contention of allocation units.
4927    pub fn isolation_bitmap(&self) -> u32 {
4928        self.ebx
4929    }
4930
4931    /// Highest COS number supported for this Leaf.
4932    pub fn highest_cos(&self) -> u16 {
4933        get_bits(self.edx, 0, 15) as u16
4934    }
4935
4936    check_bit_fn!(
4937        doc = "Is Code and Data Prioritization Technology supported?",
4938        has_code_data_prioritization,
4939        ecx,
4940        2
4941    );
4942}
4943
4944impl Debug for L3CatInfo {
4945    fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
4946        f.debug_struct("L3CatInfo")
4947            .field("capacity_mask_length", &self.capacity_mask_length())
4948            .field("isolation_bitmap", &self.isolation_bitmap())
4949            .field("highest_cos", &self.highest_cos())
4950            .finish()
4951    }
4952}
4953
4954/// L2 Cache Allocation Technology Enumeration Sub-leaf (LEAF=0x10, SUBLEAF=2).
4955#[derive(Eq, PartialEq)]
4956pub struct L2CatInfo {
4957    eax: u32,
4958    ebx: u32,
4959    edx: u32,
4960}
4961
4962impl L2CatInfo {
4963    /// Length of the capacity bit mask.
4964    pub fn capacity_mask_length(&self) -> u8 {
4965        (get_bits(self.eax, 0, 4) + 1) as u8
4966    }
4967
4968    /// Bit-granular map of isolation/contention of allocation units.
4969    pub fn isolation_bitmap(&self) -> u32 {
4970        self.ebx
4971    }
4972
4973    /// Highest COS number supported for this Leaf.
4974    pub fn highest_cos(&self) -> u16 {
4975        get_bits(self.edx, 0, 15) as u16
4976    }
4977}
4978
4979impl Debug for L2CatInfo {
4980    fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
4981        f.debug_struct("L2CatInfo")
4982            .field("capacity_mask_length", &self.capacity_mask_length())
4983            .field("isolation_bitmap", &self.isolation_bitmap())
4984            .field("highest_cos", &self.highest_cos())
4985            .finish()
4986    }
4987}
4988
4989/// Memory Bandwidth Allocation Enumeration Sub-leaf (LEAF=0x10, SUBLEAF=3).
4990#[derive(Eq, PartialEq)]
4991pub struct MemBwAllocationInfo {
4992    eax: u32,
4993    ecx: u32,
4994    edx: u32,
4995}
4996
4997impl MemBwAllocationInfo {
4998    /// Reports the maximum MBA throttling value supported for the corresponding ResID.
4999    pub fn max_hba_throttling(&self) -> u16 {
5000        (get_bits(self.eax, 0, 11) + 1) as u16
5001    }
5002
5003    /// Highest COS number supported for this Leaf.
5004    pub fn highest_cos(&self) -> u16 {
5005        get_bits(self.edx, 0, 15) as u16
5006    }
5007
5008    check_bit_fn!(
5009        doc = "Reports whether the response of the delay values is linear.",
5010        has_linear_response_delay,
5011        ecx,
5012        2
5013    );
5014}
5015
5016impl Debug for MemBwAllocationInfo {
5017    fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
5018        f.debug_struct("MemBwAllocationInfo")
5019            .field("max_hba_throttling", &self.max_hba_throttling())
5020            .field("highest_cos", &self.highest_cos())
5021            .field(
5022                "has_linear_response_delay",
5023                &self.has_linear_response_delay(),
5024            )
5025            .finish()
5026    }
5027}
5028
5029/// Intel SGX Capability Enumeration Leaf (LEAF=0x12).
5030///
5031/// Two sub-leafs: (EAX = 12H, ECX = 0 and ECX = 1)
5032///
5033/// # Platforms
5034/// ❌ AMD ✅ Intel
5035pub struct SgxInfo<R: CpuIdReader> {
5036    read: R,
5037    eax: u32,
5038    ebx: u32,
5039    _ecx: u32,
5040    edx: u32,
5041    eax1: u32,
5042    ebx1: u32,
5043    ecx1: u32,
5044    edx1: u32,
5045}
5046
5047impl<F: CpuIdReader> SgxInfo<F> {
5048    check_bit_fn!(doc = "Has SGX1 support.", has_sgx1, eax, 0);
5049    check_bit_fn!(doc = "Has SGX2 support.", has_sgx2, eax, 1);
5050
5051    check_bit_fn!(
5052        doc = "Supports ENCLV instruction leaves EINCVIRTCHILD, EDECVIRTCHILD, and ESETCONTEXT.",
5053        has_enclv_leaves_einvirtchild_edecvirtchild_esetcontext,
5054        eax,
5055        5
5056    );
5057
5058    check_bit_fn!(
5059        doc = "Supports ENCLS instruction leaves ETRACKC, ERDINFO, ELDBC, and ELDUC.",
5060        has_encls_leaves_etrackc_erdinfo_eldbc_elduc,
5061        eax,
5062        6
5063    );
5064
5065    /// Bit vector of supported extended SGX features.
5066    pub fn miscselect(&self) -> u32 {
5067        self.ebx
5068    }
5069
5070    ///  The maximum supported enclave size in non-64-bit mode is 2^retval.
5071    pub fn max_enclave_size_non_64bit(&self) -> u8 {
5072        get_bits(self.edx, 0, 7) as u8
5073    }
5074
5075    ///  The maximum supported enclave size in 64-bit mode is 2^retval.
5076    pub fn max_enclave_size_64bit(&self) -> u8 {
5077        get_bits(self.edx, 8, 15) as u8
5078    }
5079
5080    /// Reports the valid bits of SECS.ATTRIBUTES\[127:0\] that software can set with ECREATE.
5081    pub fn secs_attributes(&self) -> (u64, u64) {
5082        let lower = self.eax1 as u64 | (self.ebx1 as u64) << 32;
5083        let upper = self.ecx1 as u64 | (self.edx1 as u64) << 32;
5084        (lower, upper)
5085    }
5086    /// Iterator over SGX sub-leafs.
5087    pub fn iter(&self) -> SgxSectionIter<F> {
5088        SgxSectionIter {
5089            read: self.read.clone(),
5090            current: 2,
5091        }
5092    }
5093}
5094
5095impl<R: CpuIdReader> Debug for SgxInfo<R> {
5096    fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
5097        f.debug_struct("SgxInfo")
5098            .field("has_sgx1", &self.has_sgx1())
5099            .field("has_sgx2", &self.has_sgx2())
5100            .field("miscselect", &self.miscselect())
5101            .field(
5102                "max_enclave_size_non_64bit",
5103                &self.max_enclave_size_non_64bit(),
5104            )
5105            .field("max_enclave_size_64bit", &self.max_enclave_size_64bit())
5106            .field(
5107                "has_encls_leaves_etrackc_erdinfo_eldbc_elduc",
5108                &self.has_encls_leaves_etrackc_erdinfo_eldbc_elduc(),
5109            )
5110            .field(
5111                "has_enclv_leaves_einvirtchild_edecvirtchild_esetcontext",
5112                &self.has_enclv_leaves_einvirtchild_edecvirtchild_esetcontext(),
5113            )
5114            .field("sgx_section_iter", &self.iter())
5115            .finish()
5116    }
5117}
5118
5119/// Iterator over the SGX sub-leafs (ECX >= 2).
5120#[derive(Clone)]
5121pub struct SgxSectionIter<R: CpuIdReader> {
5122    read: R,
5123    current: u32,
5124}
5125
5126impl<R: CpuIdReader> Iterator for SgxSectionIter<R> {
5127    type Item = SgxSectionInfo;
5128
5129    fn next(&mut self) -> Option<SgxSectionInfo> {
5130        let res = self.read.cpuid2(EAX_SGX, self.current);
5131        self.current += 1;
5132        match get_bits(res.eax, 0, 3) {
5133            0b0001 => Some(SgxSectionInfo::Epc(EpcSection {
5134                eax: res.eax,
5135                ebx: res.ebx,
5136                ecx: res.ecx,
5137                edx: res.edx,
5138            })),
5139            _ => None,
5140        }
5141    }
5142}
5143
5144impl<R: CpuIdReader> Debug for SgxSectionIter<R> {
5145    fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
5146        let mut debug = f.debug_list();
5147        self.clone().for_each(|ref item| {
5148            debug.entry(item);
5149        });
5150        debug.finish()
5151    }
5152}
5153
5154/// Intel SGX EPC Enumeration Leaf
5155///
5156/// Sub-leaves 2 or higher.
5157#[derive(Debug)]
5158pub enum SgxSectionInfo {
5159    // This would be nice: https://github.com/rust-lang/rfcs/pull/1450
5160    Epc(EpcSection),
5161}
5162
5163/// EBX:EAX and EDX:ECX provide information on the Enclave Page Cache (EPC) section
5164#[derive(Debug)]
5165pub struct EpcSection {
5166    eax: u32,
5167    ebx: u32,
5168    ecx: u32,
5169    edx: u32,
5170}
5171
5172impl EpcSection {
5173    /// The physical address of the base of the EPC section
5174    pub fn physical_base(&self) -> u64 {
5175        let lower = (get_bits(self.eax, 12, 31) << 12) as u64;
5176        let upper = (get_bits(self.ebx, 0, 19) as u64) << 32;
5177        lower | upper
5178    }
5179
5180    /// Size of the corresponding EPC section within the Processor Reserved Memory.
5181    pub fn size(&self) -> u64 {
5182        let lower = (get_bits(self.ecx, 12, 31) << 12) as u64;
5183        let upper = (get_bits(self.edx, 0, 19) as u64) << 32;
5184        lower | upper
5185    }
5186}
5187
5188/// Intel Processor Trace Information (LEAF=0x14).
5189///
5190/// # Platforms
5191/// ❌ AMD ✅ Intel
5192pub struct ProcessorTraceInfo {
5193    _eax: u32,
5194    ebx: u32,
5195    ecx: u32,
5196    _edx: u32,
5197    leaf1: Option<CpuIdResult>,
5198}
5199
5200impl ProcessorTraceInfo {
5201    // EBX features
5202    check_bit_fn!(
5203        doc = "If true, Indicates that IA32_RTIT_CTL.CR3Filter can be set to 1, and \
5204               that IA32_RTIT_CR3_MATCH MSR can be accessed.",
5205        has_rtit_cr3_match,
5206        ebx,
5207        0
5208    );
5209    check_bit_fn!(
5210        doc = "If true, Indicates support of Configurable PSB and Cycle-Accurate Mode.",
5211        has_configurable_psb_and_cycle_accurate_mode,
5212        ebx,
5213        1
5214    );
5215    check_bit_fn!(
5216        doc = "If true, Indicates support of IP Filtering, TraceStop filtering, and \
5217               preservation of Intel PT MSRs across warm reset.",
5218        has_ip_tracestop_filtering,
5219        ebx,
5220        2
5221    );
5222    check_bit_fn!(
5223        doc = "If true, Indicates support of MTC timing packet and suppression of \
5224               COFI-based packets.",
5225        has_mtc_timing_packet_coefi_suppression,
5226        ebx,
5227        3
5228    );
5229
5230    check_bit_fn!(
5231        doc = "Indicates support of PTWRITE. Writes can set IA32_RTIT_CTL\\[12\\] (PTWEn \
5232               and IA32_RTIT_CTL\\[5\\] (FUPonPTW), and PTWRITE can generate packets",
5233        has_ptwrite,
5234        ebx,
5235        4
5236    );
5237
5238    check_bit_fn!(
5239        doc = "Support of Power Event Trace. Writes can set IA32_RTIT_CTL\\[4\\] (PwrEvtEn) \
5240               enabling Power Event Trace packet generation.",
5241        has_power_event_trace,
5242        ebx,
5243        5
5244    );
5245
5246    // ECX features
5247    check_bit_fn!(
5248        doc = "If true, Tracing can be enabled with IA32_RTIT_CTL.ToPA = 1, hence \
5249               utilizing the ToPA output scheme; IA32_RTIT_OUTPUT_BASE and \
5250               IA32_RTIT_OUTPUT_MASK_PTRS MSRs can be accessed.",
5251        has_topa,
5252        ecx,
5253        0
5254    );
5255    check_bit_fn!(
5256        doc = "If true, ToPA tables can hold any number of output entries, up to the \
5257               maximum allowed by the MaskOrTableOffset field of \
5258               IA32_RTIT_OUTPUT_MASK_PTRS.",
5259        has_topa_maximum_entries,
5260        ecx,
5261        1
5262    );
5263    check_bit_fn!(
5264        doc = "If true, Indicates support of Single-Range Output scheme.",
5265        has_single_range_output_scheme,
5266        ecx,
5267        2
5268    );
5269    check_bit_fn!(
5270        doc = "If true, Indicates support of output to Trace Transport subsystem.",
5271        has_trace_transport_subsystem,
5272        ecx,
5273        3
5274    );
5275    check_bit_fn!(
5276        doc = "If true, Generated packets which contain IP payloads have LIP values, \
5277               which include the CS base component.",
5278        has_lip_with_cs_base,
5279        ecx,
5280        31
5281    );
5282
5283    /// Number of configurable Address Ranges for filtering (Bits 2:0).
5284    pub fn configurable_address_ranges(&self) -> u8 {
5285        self.leaf1.map_or(0, |res| get_bits(res.eax, 0, 2) as u8)
5286    }
5287
5288    /// Bitmap of supported MTC period encodings (Bit 31:16).
5289    pub fn supported_mtc_period_encodings(&self) -> u16 {
5290        self.leaf1.map_or(0, |res| get_bits(res.eax, 16, 31) as u16)
5291    }
5292
5293    /// Bitmap of supported Cycle Threshold value encodings (Bits 15-0).
5294    pub fn supported_cycle_threshold_value_encodings(&self) -> u16 {
5295        self.leaf1.map_or(0, |res| get_bits(res.ebx, 0, 15) as u16)
5296    }
5297
5298    /// Bitmap of supported Configurable PSB frequency encodings (Bit 31:16)
5299    pub fn supported_psb_frequency_encodings(&self) -> u16 {
5300        self.leaf1.map_or(0, |res| get_bits(res.ebx, 16, 31) as u16)
5301    }
5302}
5303
5304impl Debug for ProcessorTraceInfo {
5305    fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
5306        f.debug_struct("ProcessorTraceInfo")
5307            .field(
5308                "configurable_address_ranges",
5309                &self.configurable_address_ranges(),
5310            )
5311            .field(
5312                "supported_mtc_period_encodings",
5313                &self.supported_mtc_period_encodings(),
5314            )
5315            .field(
5316                "supported_cycle_threshold_value_encodings",
5317                &self.supported_cycle_threshold_value_encodings(),
5318            )
5319            .field(
5320                "supported_psb_frequency_encodings",
5321                &self.supported_psb_frequency_encodings(),
5322            )
5323            .finish()
5324    }
5325}
5326
5327/// Time Stamp Counter/Core Crystal Clock Information (LEAF=0x15).
5328///
5329/// # Platforms
5330/// ❌ AMD ✅ Intel
5331pub struct TscInfo {
5332    eax: u32,
5333    ebx: u32,
5334    ecx: u32,
5335}
5336
5337impl fmt::Debug for TscInfo {
5338    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
5339        f.debug_struct("TscInfo")
5340            .field("denominator", &self.denominator())
5341            .field("numerator", &self.numerator())
5342            .field("nominal_frequency", &self.nominal_frequency())
5343            .field("tsc_frequency", &self.tsc_frequency())
5344            .finish()
5345    }
5346}
5347
5348impl TscInfo {
5349    /// An unsigned integer which is the denominator of the TSC/”core crystal clock” ratio.
5350    pub fn denominator(&self) -> u32 {
5351        self.eax
5352    }
5353
5354    /// An unsigned integer which is the numerator of the TSC/”core crystal clock” ratio.
5355    ///
5356    /// If this is 0, the TSC/”core crystal clock” ratio is not enumerated.
5357    pub fn numerator(&self) -> u32 {
5358        self.ebx
5359    }
5360
5361    /// An unsigned integer which is the nominal frequency of the core crystal clock in Hz.
5362    ///
5363    /// If this is 0, the nominal core crystal clock frequency is not enumerated.
5364    pub fn nominal_frequency(&self) -> u32 {
5365        self.ecx
5366    }
5367
5368    /// “TSC frequency” = “core crystal clock frequency” * EBX/EAX.
5369    pub fn tsc_frequency(&self) -> Option<u64> {
5370        // In some case TscInfo is a valid leaf, but the values reported are still 0
5371        // we should avoid a division by zero in case denominator ends up being 0.
5372        if self.nominal_frequency() == 0 || self.numerator() == 0 || self.denominator() == 0 {
5373            return None;
5374        }
5375
5376        Some(self.nominal_frequency() as u64 * self.numerator() as u64 / self.denominator() as u64)
5377    }
5378}
5379
5380/// Processor Frequency Information (LEAF=0x16).
5381///
5382/// # Platforms
5383/// ❌ AMD ✅ Intel
5384pub struct ProcessorFrequencyInfo {
5385    eax: u32,
5386    ebx: u32,
5387    ecx: u32,
5388}
5389
5390impl ProcessorFrequencyInfo {
5391    /// Processor Base Frequency (in MHz).
5392    pub fn processor_base_frequency(&self) -> u16 {
5393        get_bits(self.eax, 0, 15) as u16
5394    }
5395
5396    /// Maximum Frequency (in MHz).
5397    pub fn processor_max_frequency(&self) -> u16 {
5398        get_bits(self.ebx, 0, 15) as u16
5399    }
5400
5401    /// Bus (Reference) Frequency (in MHz).
5402    pub fn bus_frequency(&self) -> u16 {
5403        get_bits(self.ecx, 0, 15) as u16
5404    }
5405}
5406
5407impl fmt::Debug for ProcessorFrequencyInfo {
5408    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
5409        f.debug_struct("ProcessorFrequencyInfo")
5410            .field("processor_base_frequency", &self.processor_base_frequency())
5411            .field("processor_max_frequency", &self.processor_max_frequency())
5412            .field("bus_frequency", &self.bus_frequency())
5413            .finish()
5414    }
5415}
5416
5417/// Deterministic Address Translation Structure Iterator (LEAF=0x18).
5418///
5419/// # Platforms
5420/// ❌ AMD ✅ Intel
5421#[derive(Clone)]
5422pub struct DatIter<R: CpuIdReader> {
5423    read: R,
5424    current: u32,
5425    count: u32,
5426}
5427
5428impl<R: CpuIdReader> Iterator for DatIter<R> {
5429    type Item = DatInfo;
5430
5431    /// Iterate over each sub-leaf with an address translation structure.
5432    fn next(&mut self) -> Option<DatInfo> {
5433        loop {
5434            // Sub-leaf index n is invalid if n exceeds the value that sub-leaf 0 returns in EAX
5435            if self.current > self.count {
5436                return None;
5437            }
5438
5439            let res = self
5440                .read
5441                .cpuid2(EAX_DETERMINISTIC_ADDRESS_TRANSLATION_INFO, self.current);
5442            self.current += 1;
5443
5444            // A sub-leaf index is also invalid if EDX[4:0] returns 0.
5445            if get_bits(res.edx, 0, 4) == 0 {
5446                // Valid sub-leaves do not need to be contiguous or in any particular order.
5447                // A valid sub-leaf may be in a higher input ECX value than an invalid sub-leaf
5448                // or than a valid sub-leaf of a higher or lower-level struc-ture
5449                continue;
5450            }
5451
5452            return Some(DatInfo {
5453                _eax: res.eax,
5454                ebx: res.ebx,
5455                ecx: res.ecx,
5456                edx: res.edx,
5457            });
5458        }
5459    }
5460}
5461
5462impl<R: CpuIdReader> Debug for DatIter<R> {
5463    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
5464        let mut debug = f.debug_list();
5465        self.clone().for_each(|ref item| {
5466            debug.entry(item);
5467        });
5468        debug.finish()
5469    }
5470}
5471
5472/// Deterministic Address Translation Structure
5473pub struct DatInfo {
5474    _eax: u32,
5475    ebx: u32,
5476    ecx: u32,
5477    edx: u32,
5478}
5479
5480impl DatInfo {
5481    check_bit_fn!(
5482        doc = "4K page size entries supported by this structure",
5483        has_4k_entries,
5484        ebx,
5485        0
5486    );
5487
5488    check_bit_fn!(
5489        doc = "2MB page size entries supported by this structure",
5490        has_2mb_entries,
5491        ebx,
5492        1
5493    );
5494
5495    check_bit_fn!(
5496        doc = "4MB page size entries supported by this structure",
5497        has_4mb_entries,
5498        ebx,
5499        2
5500    );
5501
5502    check_bit_fn!(
5503        doc = "1GB page size entries supported by this structure",
5504        has_1gb_entries,
5505        ebx,
5506        3
5507    );
5508
5509    check_bit_fn!(
5510        doc = "Fully associative structure",
5511        is_fully_associative,
5512        edx,
5513        8
5514    );
5515
5516    /// Partitioning (0: Soft partitioning between the logical processors sharing this structure).
5517    pub fn partitioning(&self) -> u8 {
5518        get_bits(self.ebx, 8, 10) as u8
5519    }
5520
5521    /// Ways of associativity.
5522    pub fn ways(&self) -> u16 {
5523        get_bits(self.ebx, 16, 31) as u16
5524    }
5525
5526    /// Number of Sets.
5527    pub fn sets(&self) -> u32 {
5528        self.ecx
5529    }
5530
5531    /// Translation cache type field.
5532    pub fn cache_type(&self) -> DatType {
5533        match get_bits(self.edx, 0, 4) as u8 {
5534            0b00001 => DatType::DataTLB,
5535            0b00010 => DatType::InstructionTLB,
5536            0b00011 => DatType::UnifiedTLB,
5537            0b00000 => DatType::Null, // should never be returned as this indicates invalid struct!
5538            0b00100 => DatType::LoadOnly,
5539            0b00101 => DatType::StoreOnly,
5540            _ => DatType::Unknown,
5541        }
5542    }
5543
5544    /// Translation cache level (starts at 1)
5545    pub fn cache_level(&self) -> u8 {
5546        get_bits(self.edx, 5, 7) as u8
5547    }
5548
5549    /// Maximum number of addressable IDs for logical processors sharing this translation cache
5550    pub fn max_addressable_ids(&self) -> u16 {
5551        // Add one to the return value to get the result:
5552        (get_bits(self.edx, 14, 25) + 1) as u16
5553    }
5554}
5555
5556impl Debug for DatInfo {
5557    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
5558        f.debug_struct("DatInfo")
5559            .field("has_4k_entries", &self.has_4k_entries())
5560            .field("has_2mb_entries", &self.has_2mb_entries())
5561            .field("has_4mb_entries", &self.has_4mb_entries())
5562            .field("has_1gb_entries", &self.has_1gb_entries())
5563            .field("is_fully_associative", &self.is_fully_associative())
5564            .finish()
5565    }
5566}
5567
5568/// Deterministic Address Translation cache type (EDX bits 04 -- 00)
5569#[derive(Eq, PartialEq, Debug)]
5570pub enum DatType {
5571    /// Null (indicates this sub-leaf is not valid).
5572    Null = 0b00000,
5573    DataTLB = 0b00001,
5574    InstructionTLB = 0b00010,
5575    /// Some unified TLBs will allow a single TLB entry to satisfy data read/write
5576    /// and instruction fetches. Others will require separate entries (e.g., one
5577    /// loaded on data read/write and another loaded on an instruction fetch) .
5578    /// Please see the Intel® 64 and IA-32 Architectures Optimization Reference Manual
5579    /// for details of a particular product.
5580    UnifiedTLB = 0b00011,
5581    LoadOnly = 0b0100,
5582    StoreOnly = 0b0101,
5583    Unknown,
5584}
5585
5586impl fmt::Display for DatType {
5587    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
5588        let t = match self {
5589            DatType::Null => "invalid (0)",
5590            DatType::DataTLB => "Data TLB",
5591            DatType::InstructionTLB => "Instruction TLB",
5592            DatType::UnifiedTLB => "Unified TLB",
5593            DatType::LoadOnly => "Load Only",
5594            DatType::StoreOnly => "Store Only",
5595            DatType::Unknown => "Unknown",
5596        };
5597        f.write_str(t)
5598    }
5599}
5600
5601/// SoC vendor specific information (LEAF=0x17).
5602///
5603/// # Platforms
5604/// ❌ AMD ✅ Intel
5605pub struct SoCVendorInfo<R: CpuIdReader> {
5606    read: R,
5607    /// MaxSOCID_Index
5608    eax: u32,
5609    ebx: u32,
5610    ecx: u32,
5611    edx: u32,
5612}
5613
5614impl<R: CpuIdReader> SoCVendorInfo<R> {
5615    pub fn get_soc_vendor_id(&self) -> u16 {
5616        get_bits(self.ebx, 0, 15) as u16
5617    }
5618
5619    pub fn get_project_id(&self) -> u32 {
5620        self.ecx
5621    }
5622
5623    pub fn get_stepping_id(&self) -> u32 {
5624        self.edx
5625    }
5626
5627    pub fn get_vendor_brand(&self) -> Option<SoCVendorBrand> {
5628        // Leaf 17H is valid if MaxSOCID_Index >= 3.
5629        if self.eax >= 3 {
5630            let r1 = self.read.cpuid2(EAX_SOC_VENDOR_INFO, 1);
5631            let r2 = self.read.cpuid2(EAX_SOC_VENDOR_INFO, 2);
5632            let r3 = self.read.cpuid2(EAX_SOC_VENDOR_INFO, 3);
5633            Some(SoCVendorBrand { data: [r1, r2, r3] })
5634        } else {
5635            None
5636        }
5637    }
5638
5639    pub fn get_vendor_attributes(&self) -> Option<SoCVendorAttributesIter<R>> {
5640        if self.eax > 3 {
5641            Some(SoCVendorAttributesIter {
5642                read: self.read.clone(),
5643                count: self.eax,
5644                current: 3,
5645            })
5646        } else {
5647            None
5648        }
5649    }
5650}
5651
5652impl<R: CpuIdReader> fmt::Debug for SoCVendorInfo<R> {
5653    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
5654        f.debug_struct("SoCVendorInfo")
5655            .field("soc_vendor_id", &self.get_soc_vendor_id())
5656            .field("project_id", &self.get_project_id())
5657            .field("stepping_id", &self.get_stepping_id())
5658            .field("vendor_brand", &self.get_vendor_brand())
5659            .field("vendor_attributes", &self.get_vendor_attributes())
5660            .finish()
5661    }
5662}
5663
5664/// Iterator for SoC vendor attributes.
5665pub struct SoCVendorAttributesIter<R: CpuIdReader> {
5666    read: R,
5667    count: u32,
5668    current: u32,
5669}
5670
5671impl<R: CpuIdReader> fmt::Debug for SoCVendorAttributesIter<R> {
5672    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
5673        f.debug_struct("SocVendorAttributesIter")
5674            .field("count", &self.count)
5675            .field("current", &self.current)
5676            .finish()
5677    }
5678}
5679
5680impl<R: CpuIdReader> Iterator for SoCVendorAttributesIter<R> {
5681    type Item = CpuIdResult;
5682
5683    /// Iterate over all SoC vendor specific attributes.
5684    fn next(&mut self) -> Option<CpuIdResult> {
5685        if self.current > self.count {
5686            return None;
5687        }
5688        self.count += 1;
5689        Some(self.read.cpuid2(EAX_SOC_VENDOR_INFO, self.count))
5690    }
5691}
5692
5693/// A vendor brand string as queried from the cpuid leaf.
5694#[derive(Debug, PartialEq, Eq)]
5695#[repr(C)]
5696pub struct SoCVendorBrand {
5697    data: [CpuIdResult; 3],
5698}
5699
5700impl SoCVendorBrand {
5701    /// Return the SocVendorBrand as a string.
5702    pub fn as_str(&self) -> &str {
5703        let brand_string_start = self as *const SoCVendorBrand as *const u8;
5704        let slice = unsafe {
5705            // Safety: SoCVendorBrand is laid out with repr(C).
5706            slice::from_raw_parts(brand_string_start, size_of::<SoCVendorBrand>())
5707        };
5708        str::from_utf8(slice).unwrap_or("InvalidSoCVendorString")
5709    }
5710
5711    #[deprecated(
5712        since = "10.0.0",
5713        note = "Use idiomatic function name `as_str` instead"
5714    )]
5715    pub fn as_string(&self) -> &str {
5716        self.as_str()
5717    }
5718}
5719
5720impl fmt::Display for SoCVendorBrand {
5721    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
5722        write!(f, "{}", self.as_str())
5723    }
5724}
5725
5726/// Information about Hypervisor (LEAF=0x4000_0001)
5727///
5728/// More information about this semi-official leaf can be found here
5729/// <https://lwn.net/Articles/301888/>
5730pub struct HypervisorInfo<R: CpuIdReader> {
5731    read: R,
5732    res: CpuIdResult,
5733}
5734
5735impl<R: CpuIdReader> fmt::Debug for HypervisorInfo<R> {
5736    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
5737        f.debug_struct("HypervisorInfo")
5738            .field("identify", &self.identify())
5739            .field("tsc_frequency", &self.tsc_frequency())
5740            .field("apic_frequency", &self.apic_frequency())
5741            .finish()
5742    }
5743}
5744
5745/// Identifies the different Hypervisor products.
5746#[derive(Debug, Eq, PartialEq)]
5747pub enum Hypervisor {
5748    Xen,
5749    VMware,
5750    HyperV,
5751    KVM,
5752    /// QEMU is the hypervisor identity when QEMU is used
5753    /// without an accelerator, such as KVM.
5754    QEMU,
5755    Bhyve,
5756    QNX,
5757    ACRN,
5758    Unknown(u32, u32, u32),
5759}
5760
5761impl<R: CpuIdReader> HypervisorInfo<R> {
5762    /// Returns the identity of the [`Hypervisor`].
5763    ///
5764    /// ## Technical Background
5765    ///
5766    /// The value is a 12-byte (12 character) fixed-length ASCII string.
5767    ///
5768    /// Usually all of these IDs can be found in the original source code on
5769    /// Github relatively easy (if the project is open source). Once you
5770    /// have an ID, you find cumulated lists with all kinds of IDs on Github
5771    /// relatively easy.
5772    pub fn identify(&self) -> Hypervisor {
5773        match (self.res.ebx, self.res.ecx, self.res.edx) {
5774            // "VMwareVMware" (0x56 => V, 0x4d => M, ...)
5775            (0x61774d56, 0x4d566572, 0x65726177) => Hypervisor::VMware,
5776            // "XenVMMXenVMM"
5777            (0x566e6558, 0x65584d4d, 0x4d4d566e) => Hypervisor::Xen,
5778            // "Microsoft Hv"
5779            (0x7263694d, 0x666f736f, 0x76482074) => Hypervisor::HyperV,
5780            // "KVMKVMKVM\0\0\0"
5781            (0x4b4d564b, 0x564b4d56, 0x0000004d) => Hypervisor::KVM,
5782            // "TCGTCGTCGTCG"
5783            // see https://github.com/qemu/qemu/blob/6512fa497c2fa9751b9d774ab32d87a9764d1958/target/i386/cpu.c
5784            (0x54474354, 0x43544743, 0x47435447) => Hypervisor::QEMU,
5785            // "bhyve bhyve "
5786            // found this in another library ("heim-virt")
5787            (0x76796862, 0x68622065, 0x20657679) => Hypervisor::Bhyve,
5788            // "BHyVE BHyVE "
5789            // But this value is in the original source code. To be safe, we keep both.
5790            // See https://github.com/lattera/bhyve/blob/5946a9115d2771a1d27f14a835c7fbc05b30f7f9/sys/amd64/vmm/x86.c#L165
5791            (0x56794842, 0x48422045, 0x20455679) => Hypervisor::Bhyve,
5792            // "QNXQVMBSQG"
5793            // This can be verified in multiple Git repos (e.g. by Intel)
5794            // https://github.com/search?q=QNXQVMBSQG&type=code
5795            (0x51584e51, 0x53424d56, 0x00004751) => Hypervisor::QNX,
5796            // "ACRNACRNACRN"
5797            (0x4e524341, 0x4e524341, 0x4e524341) => Hypervisor::ACRN,
5798            (ebx, ecx, edx) => Hypervisor::Unknown(ebx, ecx, edx),
5799        }
5800    }
5801
5802    /// TSC frequency in kHz.
5803    pub fn tsc_frequency(&self) -> Option<u32> {
5804        // vm aware tsc frequency retrieval:
5805        // # EAX: (Virtual) TSC frequency in kHz.
5806        if self.res.eax >= 0x40000010 {
5807            let virt_tinfo = self.read.cpuid2(0x40000010, 0);
5808            Some(virt_tinfo.eax)
5809        } else {
5810            None
5811        }
5812    }
5813
5814    /// (Virtual) Bus (local apic timer) frequency in kHz.
5815    pub fn apic_frequency(&self) -> Option<u32> {
5816        // # EBX: (Virtual) Bus (local apic timer) frequency in kHz.
5817        if self.res.eax >= 0x40000010 {
5818            let virt_tinfo = self.read.cpuid2(0x40000010, 0);
5819            Some(virt_tinfo.ebx)
5820        } else {
5821            None
5822        }
5823    }
5824}
5825
5826#[cfg(doctest)]
5827mod test_readme {
5828    macro_rules! external_doc_test {
5829        ($x:expr) => {
5830            #[doc = $x]
5831            extern "C" {}
5832        };
5833    }
5834
5835    external_doc_test!(include_str!("../README.md"));
5836}