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