raw_cpuid/
lib.rs

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