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