Coverage Report

Created: 2026-06-07 06:39

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