1#![cfg_attr(not(feature = "std"), no_std)]
48#![crate_name = "raw_cpuid"]
49#![crate_type = "lib"]
50
51#[cfg(test)]
52#[macro_use]
53extern crate std;
54
55#[cfg(feature = "display")]
56pub mod display;
57mod extended;
58#[cfg(test)]
59mod tests;
60
61use bitflags::bitflags;
62use core::fmt::{self, Debug, Formatter};
63use core::mem::size_of;
64use core::slice;
65use core::str;
66
67#[cfg(feature = "serialize")]
68use serde_derive::{Deserialize, Serialize};
69
70pub use extended::*;
71
72#[cfg(any(
74 all(target_arch = "x86", not(target_env = "sgx"), target_feature = "sse"),
75 all(target_arch = "x86_64", not(target_env = "sgx"))
76))]
77pub mod native_cpuid {
78 use crate::CpuIdResult;
79
80 #[cfg(all(target_arch = "x86", not(target_env = "sgx"), target_feature = "sse"))]
81 use core::arch::x86 as arch;
82 #[cfg(all(target_arch = "x86_64", not(target_env = "sgx")))]
83 use core::arch::x86_64 as arch;
84
85 pub fn cpuid_count(a: u32, c: u32) -> CpuIdResult {
86 let result = unsafe { self::arch::__cpuid_count(a, c) };
89
90 CpuIdResult {
91 eax: result.eax,
92 ebx: result.ebx,
93 ecx: result.ecx,
94 edx: result.edx,
95 }
96 }
97 #[derive(Clone, Copy)]
100 pub struct CpuIdReaderNative;
101
102 impl super::CpuIdReader for CpuIdReaderNative {
103 fn cpuid2(&self, eax: u32, ecx: u32) -> CpuIdResult {
104 cpuid_count(eax, ecx)
105 }
106 }
107}
108
109#[cfg(any(
110 all(target_arch = "x86", not(target_env = "sgx"), target_feature = "sse"),
111 all(target_arch = "x86_64", not(target_env = "sgx"))
112))]
113pub use native_cpuid::CpuIdReaderNative;
114
115#[cfg(any(
120 all(target_arch = "x86", not(target_env = "sgx"), target_feature = "sse"),
121 all(target_arch = "x86_64", not(target_env = "sgx"))
122))]
123#[macro_export]
124macro_rules! cpuid {
125 ($eax:expr) => {
126 $crate::native_cpuid::cpuid_count($eax as u32, 0)
127 };
128
129 ($eax:expr, $ecx:expr) => {
130 $crate::native_cpuid::cpuid_count($eax as u32, $ecx as u32)
131 };
132}
133
134fn get_bits(r: u32, from: u32, to: u32) -> u32 {
135 assert!(from <= 31);
136 assert!(to <= 31);
137 assert!(from <= to);
138
139 let mask = match to {
140 31 => 0xffffffff,
141 _ => (1 << (to + 1)) - 1,
142 };
143
144 (r & mask) >> from
145}
146
147macro_rules! check_flag {
148 ($doc:meta, $fun:ident, $flags:ident, $flag:expr) => {
149 #[$doc]
150 pub fn $fun(&self) -> bool {
151 self.$flags.contains($flag)
152 }
153 };
154}
155
156macro_rules! is_bit_set {
157 ($field:expr, $bit:expr) => {
158 $field & (1 << $bit) > 0
159 };
160}
161
162macro_rules! check_bit_fn {
163 ($doc:meta, $fun:ident, $field:ident, $bit:expr) => {
164 #[$doc]
165 pub fn $fun(&self) -> bool {
166 is_bit_set!(self.$field, $bit)
167 }
168 };
169}
170
171pub trait CpuIdReader: Clone {
175 fn cpuid1(&self, eax: u32) -> CpuIdResult {
176 self.cpuid2(eax, 0)
177 }
178 fn cpuid2(&self, eax: u32, ecx: u32) -> CpuIdResult;
179}
180
181impl<F> CpuIdReader for F
182where
183 F: Fn(u32, u32) -> CpuIdResult + Clone,
184{
185 fn cpuid2(&self, eax: u32, ecx: u32) -> CpuIdResult {
186 self(eax, ecx)
187 }
188}
189
190#[derive(Debug, Eq, PartialEq, Clone, Copy)]
191enum Vendor {
192 Intel,
193 Amd,
194 Unknown(u32, u32, u32),
195}
196
197impl Vendor {
198 fn from_vendor_leaf(res: CpuIdResult) -> Self {
199 let vi = VendorInfo {
200 ebx: res.ebx,
201 ecx: res.ecx,
202 edx: res.edx,
203 };
204
205 match vi.as_str() {
206 "GenuineIntel" => Vendor::Intel,
207 "AuthenticAMD" | "HygonGenuine" => Vendor::Amd,
208 _ => Vendor::Unknown(res.ebx, res.ecx, res.edx),
209 }
210 }
211}
212
213#[derive(Clone, Copy)]
217pub struct CpuId<R: CpuIdReader> {
218 read: R,
220 vendor: Vendor,
222 supported_leafs: u32,
224 supported_extended_leafs: u32,
226}
227
228#[cfg(any(
229 all(target_arch = "x86", not(target_env = "sgx"), target_feature = "sse"),
230 all(target_arch = "x86_64", not(target_env = "sgx"))
231))]
232impl Default for CpuId<CpuIdReaderNative> {
233 fn default() -> Self {
235 CpuId::with_cpuid_fn(CpuIdReaderNative)
236 }
237}
238
239#[cfg(any(
240 all(target_arch = "x86", not(target_env = "sgx"), target_feature = "sse"),
241 all(target_arch = "x86_64", not(target_env = "sgx"))
242))]
243impl CpuId<CpuIdReaderNative> {
244 pub fn new() -> Self {
246 CpuId::default()
247 }
248}
249
250#[derive(Copy, Clone, Eq, PartialEq)]
252#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))]
253#[repr(C)]
254pub struct CpuIdResult {
255 pub eax: u32,
257 pub ebx: u32,
259 pub ecx: u32,
261 pub edx: u32,
263}
264
265impl CpuIdResult {
266 pub fn all_zero(&self) -> bool {
267 self.eax == 0 && self.ebx == 0 && self.ecx == 0 && self.edx == 0
268 }
269}
270
271impl Debug for CpuIdResult {
272 fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
273 f.debug_struct("CpuIdResult")
274 .field("eax", &(self.eax as *const u32))
275 .field("ebx", &(self.ebx as *const u32))
276 .field("ecx", &(self.ecx as *const u32))
277 .field("edx", &(self.edx as *const u32))
278 .finish()
279 }
280}
281
282const EAX_VENDOR_INFO: u32 = 0x0;
286const EAX_FEATURE_INFO: u32 = 0x1;
287const EAX_CACHE_INFO: u32 = 0x2;
288const EAX_PROCESSOR_SERIAL: u32 = 0x3;
289const EAX_CACHE_PARAMETERS: u32 = 0x4;
290const EAX_MONITOR_MWAIT_INFO: u32 = 0x5;
291const EAX_THERMAL_POWER_INFO: u32 = 0x6;
292const EAX_STRUCTURED_EXTENDED_FEATURE_INFO: u32 = 0x7;
293const EAX_DIRECT_CACHE_ACCESS_INFO: u32 = 0x9;
294const EAX_PERFORMANCE_MONITOR_INFO: u32 = 0xA;
295const EAX_EXTENDED_TOPOLOGY_INFO: u32 = 0xB;
296const EAX_EXTENDED_STATE_INFO: u32 = 0xD;
297const EAX_RDT_MONITORING: u32 = 0xF;
298const EAX_RDT_ALLOCATION: u32 = 0x10;
299const EAX_SGX: u32 = 0x12;
300const EAX_TRACE_INFO: u32 = 0x14;
301const EAX_TIME_STAMP_COUNTER_INFO: u32 = 0x15;
302const EAX_FREQUENCY_INFO: u32 = 0x16;
303const EAX_SOC_VENDOR_INFO: u32 = 0x17;
304const EAX_DETERMINISTIC_ADDRESS_TRANSLATION_INFO: u32 = 0x18;
305const EAX_EXTENDED_TOPOLOGY_INFO_V2: u32 = 0x1F;
306
307const EAX_HYPERVISOR_INFO: u32 = 0x4000_0000;
309
310const EAX_EXTENDED_FUNCTION_INFO: u32 = 0x8000_0000;
314const EAX_EXTENDED_PROCESSOR_AND_FEATURE_IDENTIFIERS: u32 = 0x8000_0001;
315const EAX_EXTENDED_BRAND_STRING: u32 = 0x8000_0002;
316const EAX_L1_CACHE_INFO: u32 = 0x8000_0005;
317const EAX_L2_L3_CACHE_INFO: u32 = 0x8000_0006;
318const EAX_ADVANCED_POWER_MGMT_INFO: u32 = 0x8000_0007;
319const EAX_PROCESSOR_CAPACITY_INFO: u32 = 0x8000_0008;
320const EAX_TLB_1GB_PAGE_INFO: u32 = 0x8000_0019;
321const EAX_PERFORMANCE_OPTIMIZATION_INFO: u32 = 0x8000_001A;
322const EAX_INSTRUCTION_BASED_SAMPLING_CAPABILITIES: u32 = 0x8000_001B;
323const EAX_CACHE_PARAMETERS_AMD: u32 = 0x8000_001D;
324const EAX_PROCESSOR_TOPOLOGY_INFO: u32 = 0x8000_001E;
325const EAX_MEMORY_ENCRYPTION_INFO: u32 = 0x8000_001F;
326const EAX_SVM_FEATURES: u32 = 0x8000_000A;
327const EAX_PQOS_EXTENDED_FEATURES: u32 = 0x8000_0020;
328const EAX_EXTENDED_FEATURE_IDENTIFICATION_2: u32 = 0x8000_0021;
329const EAX_EXTENDED_PERFORMANCE_MONITORING_AND_DEBUG: u32 = 0x8000_0022;
330const EAX_MULTI_KEY_ENCRYPTED_MEMORY_CAPABILITIES: u32 = 0x8000_0023;
331const EAX_EXTENDED_CPU_TOPOLOGY: u32 = 0x8000_0026;
332
333impl<R: CpuIdReader> CpuId<R> {
334 pub fn with_cpuid_reader(cpuid_fn: R) -> Self {
339 let vendor_leaf = cpuid_fn.cpuid1(EAX_VENDOR_INFO);
340 let extended_leaf = cpuid_fn.cpuid1(EAX_EXTENDED_FUNCTION_INFO);
341 CpuId {
342 supported_leafs: vendor_leaf.eax,
343 supported_extended_leafs: extended_leaf.eax,
344 vendor: Vendor::from_vendor_leaf(vendor_leaf),
345 read: cpuid_fn,
346 }
347 }
348
349 pub fn with_cpuid_fn(cpuid_fn: R) -> Self {
355 CpuId::with_cpuid_reader(cpuid_fn)
356 }
357
358 fn leaf_is_supported(&self, val: u32) -> bool {
360 if self.vendor == Vendor::Amd && ((0x2..=0x4).contains(&val) || (0x8..=0xa).contains(&val))
362 {
363 return false;
364 }
365
366 if val < EAX_EXTENDED_FUNCTION_INFO {
367 val <= self.supported_leafs
368 } else {
369 val <= self.supported_extended_leafs
370 }
371 }
372
373 pub fn get_vendor_info(&self) -> Option<VendorInfo> {
381 if self.leaf_is_supported(EAX_VENDOR_INFO) {
382 let res = self.read.cpuid1(EAX_VENDOR_INFO);
383 Some(VendorInfo {
384 ebx: res.ebx,
385 ecx: res.ecx,
386 edx: res.edx,
387 })
388 } else {
389 None
390 }
391 }
392
393 pub fn get_feature_info(&self) -> Option<FeatureInfo> {
398 if self.leaf_is_supported(EAX_FEATURE_INFO) {
399 let res = self.read.cpuid1(EAX_FEATURE_INFO);
400 Some(FeatureInfo {
401 vendor: self.vendor,
402 eax: res.eax,
403 ebx: res.ebx,
404 edx_ecx: FeatureInfoFlags::from_bits_truncate(
405 ((res.edx as u64) << 32) | (res.ecx as u64),
406 ),
407 })
408 } else {
409 None
410 }
411 }
412
413 pub fn get_cache_info(&self) -> Option<CacheInfoIter> {
418 if self.leaf_is_supported(EAX_CACHE_INFO) {
419 let res = self.read.cpuid1(EAX_CACHE_INFO);
420 Some(CacheInfoIter {
421 current: 1,
422 eax: res.eax,
423 ebx: res.ebx,
424 ecx: res.ecx,
425 edx: res.edx,
426 })
427 } else {
428 None
429 }
430 }
431
432 pub fn get_processor_serial(&self) -> Option<ProcessorSerial> {
437 if self.leaf_is_supported(EAX_PROCESSOR_SERIAL) {
438 let res1 = self.read.cpuid1(EAX_FEATURE_INFO);
440 let res = self.read.cpuid1(EAX_PROCESSOR_SERIAL);
441 Some(ProcessorSerial {
442 ecx: res.ecx,
443 edx: res.edx,
444 eax: res1.eax,
445 })
446 } else {
447 None
448 }
449 }
450
451 pub fn get_cache_parameters(&self) -> Option<CacheParametersIter<R>> {
460 if self.leaf_is_supported(EAX_CACHE_PARAMETERS)
461 || (self.vendor == Vendor::Amd && self.leaf_is_supported(EAX_CACHE_PARAMETERS_AMD))
462 {
463 Some(CacheParametersIter {
464 read: self.read.clone(),
465 leaf: if self.vendor == Vendor::Amd {
466 EAX_CACHE_PARAMETERS_AMD
467 } else {
468 EAX_CACHE_PARAMETERS
469 },
470 current: 0,
471 })
472 } else {
473 None
474 }
475 }
476
477 pub fn get_monitor_mwait_info(&self) -> Option<MonitorMwaitInfo> {
482 if self.leaf_is_supported(EAX_MONITOR_MWAIT_INFO) {
483 let res = self.read.cpuid1(EAX_MONITOR_MWAIT_INFO);
484 Some(MonitorMwaitInfo {
485 eax: res.eax,
486 ebx: res.ebx,
487 ecx: res.ecx,
488 edx: res.edx,
489 })
490 } else {
491 None
492 }
493 }
494
495 pub fn get_thermal_power_info(&self) -> Option<ThermalPowerInfo> {
500 if self.leaf_is_supported(EAX_THERMAL_POWER_INFO) {
501 let res = self.read.cpuid1(EAX_THERMAL_POWER_INFO);
502 Some(ThermalPowerInfo {
503 eax: ThermalPowerFeaturesEax::from_bits_truncate(res.eax),
504 ebx: res.ebx,
505 ecx: ThermalPowerFeaturesEcx::from_bits_truncate(res.ecx),
506 _edx: res.edx,
507 })
508 } else {
509 None
510 }
511 }
512
513 pub fn get_extended_feature_info(&self) -> Option<ExtendedFeatures> {
518 if self.leaf_is_supported(EAX_STRUCTURED_EXTENDED_FEATURE_INFO) {
519 let res = self.read.cpuid1(EAX_STRUCTURED_EXTENDED_FEATURE_INFO);
520 let res1 = self.read.cpuid2(EAX_STRUCTURED_EXTENDED_FEATURE_INFO, 1);
521 Some(ExtendedFeatures {
522 _eax: res.eax,
523 ebx: ExtendedFeaturesEbx::from_bits_truncate(res.ebx),
524 ecx: ExtendedFeaturesEcx::from_bits_truncate(res.ecx),
525 edx: ExtendedFeaturesEdx::from_bits_truncate(res.edx),
526 eax1: ExtendedFeaturesEax1::from_bits_truncate(res1.eax),
527 _ebx1: res1.ebx,
528 _ecx1: res1.ecx,
529 edx1: ExtendedFeaturesEdx1::from_bits_truncate(res1.edx),
530 })
531 } else {
532 None
533 }
534 }
535
536 pub fn get_direct_cache_access_info(&self) -> Option<DirectCacheAccessInfo> {
541 if self.leaf_is_supported(EAX_DIRECT_CACHE_ACCESS_INFO) {
542 let res = self.read.cpuid1(EAX_DIRECT_CACHE_ACCESS_INFO);
543 Some(DirectCacheAccessInfo { eax: res.eax })
544 } else {
545 None
546 }
547 }
548
549 pub fn get_performance_monitoring_info(&self) -> Option<PerformanceMonitoringInfo> {
554 if self.leaf_is_supported(EAX_PERFORMANCE_MONITOR_INFO) {
555 let res = self.read.cpuid1(EAX_PERFORMANCE_MONITOR_INFO);
556 Some(PerformanceMonitoringInfo {
557 eax: res.eax,
558 ebx: PerformanceMonitoringFeaturesEbx::from_bits_truncate(res.ebx),
559 _ecx: res.ecx,
560 edx: res.edx,
561 })
562 } else {
563 None
564 }
565 }
566
567 pub fn get_extended_topology_info(&self) -> Option<ExtendedTopologyIter<R>> {
576 if self.leaf_is_supported(EAX_EXTENDED_TOPOLOGY_INFO) {
577 Some(ExtendedTopologyIter {
578 read: self.read.clone(),
579 level: 0,
580 is_v2: false,
581 })
582 } else {
583 None
584 }
585 }
586
587 pub fn get_extended_topology_info_v2(&self) -> Option<ExtendedTopologyIter<R>> {
592 if self.leaf_is_supported(EAX_EXTENDED_TOPOLOGY_INFO_V2) {
593 Some(ExtendedTopologyIter {
594 read: self.read.clone(),
595 level: 0,
596 is_v2: true,
597 })
598 } else {
599 None
600 }
601 }
602
603 pub fn get_extended_state_info(&self) -> Option<ExtendedStateInfo<R>> {
608 if self.leaf_is_supported(EAX_EXTENDED_STATE_INFO) {
609 let res = self.read.cpuid2(EAX_EXTENDED_STATE_INFO, 0);
610 let res1 = self.read.cpuid2(EAX_EXTENDED_STATE_INFO, 1);
611 Some(ExtendedStateInfo {
612 read: self.read.clone(),
613 eax: ExtendedStateInfoXCR0Flags::from_bits_truncate(res.eax),
614 ebx: res.ebx,
615 ecx: res.ecx,
616 _edx: res.edx,
617 eax1: res1.eax,
618 ebx1: res1.ebx,
619 ecx1: ExtendedStateInfoXSSFlags::from_bits_truncate(res1.ecx),
620 _edx1: res1.edx,
621 })
622 } else {
623 None
624 }
625 }
626
627 pub fn get_rdt_monitoring_info(&self) -> Option<RdtMonitoringInfo<R>> {
632 let res = self.read.cpuid1(EAX_RDT_MONITORING);
633
634 if self.leaf_is_supported(EAX_RDT_MONITORING) {
635 Some(RdtMonitoringInfo {
636 read: self.read.clone(),
637 ebx: res.ebx,
638 edx: res.edx,
639 })
640 } else {
641 None
642 }
643 }
644
645 pub fn get_rdt_allocation_info(&self) -> Option<RdtAllocationInfo<R>> {
650 let res = self.read.cpuid1(EAX_RDT_ALLOCATION);
651
652 if self.leaf_is_supported(EAX_RDT_ALLOCATION) {
653 Some(RdtAllocationInfo {
654 read: self.read.clone(),
655 ebx: res.ebx,
656 })
657 } else {
658 None
659 }
660 }
661
662 pub fn get_sgx_info(&self) -> Option<SgxInfo<R>> {
667 self.get_extended_feature_info().and_then(|info| {
669 if self.leaf_is_supported(EAX_SGX) && info.has_sgx() {
670 let res = self.read.cpuid2(EAX_SGX, 0);
671 let res1 = self.read.cpuid2(EAX_SGX, 1);
672 Some(SgxInfo {
673 read: self.read.clone(),
674 eax: res.eax,
675 ebx: res.ebx,
676 _ecx: res.ecx,
677 edx: res.edx,
678 eax1: res1.eax,
679 ebx1: res1.ebx,
680 ecx1: res1.ecx,
681 edx1: res1.edx,
682 })
683 } else {
684 None
685 }
686 })
687 }
688
689 pub fn get_processor_trace_info(&self) -> Option<ProcessorTraceInfo> {
694 if self.leaf_is_supported(EAX_TRACE_INFO) {
695 let res = self.read.cpuid2(EAX_TRACE_INFO, 0);
696 let res1 = if res.eax >= 1 {
697 Some(self.read.cpuid2(EAX_TRACE_INFO, 1))
698 } else {
699 None
700 };
701
702 Some(ProcessorTraceInfo {
703 _eax: res.eax,
704 ebx: res.ebx,
705 ecx: res.ecx,
706 _edx: res.edx,
707 leaf1: res1,
708 })
709 } else {
710 None
711 }
712 }
713
714 pub fn get_tsc_info(&self) -> Option<TscInfo> {
719 if self.leaf_is_supported(EAX_TIME_STAMP_COUNTER_INFO) {
720 let res = self.read.cpuid2(EAX_TIME_STAMP_COUNTER_INFO, 0);
721 Some(TscInfo {
722 eax: res.eax,
723 ebx: res.ebx,
724 ecx: res.ecx,
725 })
726 } else {
727 None
728 }
729 }
730
731 pub fn get_processor_frequency_info(&self) -> Option<ProcessorFrequencyInfo> {
736 if self.leaf_is_supported(EAX_FREQUENCY_INFO) {
737 let res = self.read.cpuid1(EAX_FREQUENCY_INFO);
738 Some(ProcessorFrequencyInfo {
739 eax: res.eax,
740 ebx: res.ebx,
741 ecx: res.ecx,
742 })
743 } else {
744 None
745 }
746 }
747
748 pub fn get_soc_vendor_info(&self) -> Option<SoCVendorInfo<R>> {
753 if self.leaf_is_supported(EAX_SOC_VENDOR_INFO) {
754 let res = self.read.cpuid1(EAX_SOC_VENDOR_INFO);
755 Some(SoCVendorInfo {
756 read: self.read.clone(),
757 eax: res.eax,
758 ebx: res.ebx,
759 ecx: res.ecx,
760 edx: res.edx,
761 })
762 } else {
763 None
764 }
765 }
766
767 pub fn get_deterministic_address_translation_info(&self) -> Option<DatIter<R>> {
772 if self.leaf_is_supported(EAX_DETERMINISTIC_ADDRESS_TRANSLATION_INFO) {
773 let res = self
774 .read
775 .cpuid2(EAX_DETERMINISTIC_ADDRESS_TRANSLATION_INFO, 0);
776 Some(DatIter {
777 read: self.read.clone(),
778 current: 0,
779 count: res.eax,
780 })
781 } else {
782 None
783 }
784 }
785
786 pub fn get_hypervisor_info(&self) -> Option<HypervisorInfo<R>> {
792 self.get_feature_info()
795 .filter(|fi| fi.has_hypervisor())
796 .and_then(|_| {
797 let res = self.read.cpuid1(EAX_HYPERVISOR_INFO);
798 if res.eax > 0 {
799 Some(HypervisorInfo {
800 read: self.read.clone(),
801 res,
802 })
803 } else {
804 None
805 }
806 })
807 }
808
809 pub fn get_extended_processor_and_feature_identifiers(
814 &self,
815 ) -> Option<ExtendedProcessorFeatureIdentifiers> {
816 if self.leaf_is_supported(EAX_EXTENDED_PROCESSOR_AND_FEATURE_IDENTIFIERS) {
817 Some(ExtendedProcessorFeatureIdentifiers::new(
818 self.vendor,
819 self.read
820 .cpuid1(EAX_EXTENDED_PROCESSOR_AND_FEATURE_IDENTIFIERS),
821 ))
822 } else {
823 None
824 }
825 }
826
827 pub fn get_processor_brand_string(&self) -> Option<ProcessorBrandString> {
832 if self.leaf_is_supported(EAX_EXTENDED_BRAND_STRING)
833 && self.leaf_is_supported(EAX_EXTENDED_BRAND_STRING + 1)
834 && self.leaf_is_supported(EAX_EXTENDED_BRAND_STRING + 2)
835 {
836 Some(ProcessorBrandString::new([
837 self.read.cpuid1(EAX_EXTENDED_BRAND_STRING),
838 self.read.cpuid1(EAX_EXTENDED_BRAND_STRING + 1),
839 self.read.cpuid1(EAX_EXTENDED_BRAND_STRING + 2),
840 ]))
841 } else {
842 None
843 }
844 }
845
846 pub fn get_l1_cache_and_tlb_info(&self) -> Option<L1CacheTlbInfo> {
851 if self.vendor == Vendor::Amd && self.leaf_is_supported(EAX_L1_CACHE_INFO) {
852 Some(L1CacheTlbInfo::new(self.read.cpuid1(EAX_L1_CACHE_INFO)))
853 } else {
854 None
855 }
856 }
857
858 pub fn get_l2_l3_cache_and_tlb_info(&self) -> Option<L2And3CacheTlbInfo> {
863 if self.leaf_is_supported(EAX_L2_L3_CACHE_INFO) {
864 Some(L2And3CacheTlbInfo::new(
865 self.read.cpuid1(EAX_L2_L3_CACHE_INFO),
866 ))
867 } else {
868 None
869 }
870 }
871
872 pub fn get_advanced_power_mgmt_info(&self) -> Option<ApmInfo> {
877 if self.leaf_is_supported(EAX_ADVANCED_POWER_MGMT_INFO) {
878 Some(ApmInfo::new(self.read.cpuid1(EAX_ADVANCED_POWER_MGMT_INFO)))
879 } else {
880 None
881 }
882 }
883
884 pub fn get_processor_capacity_feature_info(&self) -> Option<ProcessorCapacityAndFeatureInfo> {
889 if self.leaf_is_supported(EAX_PROCESSOR_CAPACITY_INFO) {
890 Some(ProcessorCapacityAndFeatureInfo::new(
891 self.read.cpuid1(EAX_PROCESSOR_CAPACITY_INFO),
892 ))
893 } else {
894 None
895 }
896 }
897
898 pub fn get_svm_info(&self) -> Option<SvmFeatures> {
907 let has_svm = self
908 .get_extended_processor_and_feature_identifiers()
909 .map_or(false, |f| f.has_svm());
910 if has_svm && self.leaf_is_supported(EAX_SVM_FEATURES) {
911 Some(SvmFeatures::new(self.read.cpuid1(EAX_SVM_FEATURES)))
912 } else {
913 None
914 }
915 }
916
917 pub fn get_tlb_1gb_page_info(&self) -> Option<Tlb1gbPageInfo> {
922 if self.leaf_is_supported(EAX_TLB_1GB_PAGE_INFO) {
923 Some(Tlb1gbPageInfo::new(self.read.cpuid1(EAX_TLB_1GB_PAGE_INFO)))
924 } else {
925 None
926 }
927 }
928
929 pub fn get_performance_optimization_info(&self) -> Option<PerformanceOptimizationInfo> {
934 if self.leaf_is_supported(EAX_PERFORMANCE_OPTIMIZATION_INFO) {
935 Some(PerformanceOptimizationInfo::new(
936 self.read.cpuid1(EAX_PERFORMANCE_OPTIMIZATION_INFO),
937 ))
938 } else {
939 None
940 }
941 }
942
943 pub fn get_instruction_based_sampling_capabilities(
948 &self,
949 ) -> Option<InstructionBasedSamplingCapabilities> {
950 if self.leaf_is_supported(EAX_INSTRUCTION_BASED_SAMPLING_CAPABILITIES) {
951 Some(InstructionBasedSamplingCapabilities::new(
952 self.read
953 .cpuid1(EAX_INSTRUCTION_BASED_SAMPLING_CAPABILITIES),
954 ))
955 } else {
956 None
957 }
958 }
959
960 pub fn get_processor_topology_info(&self) -> Option<ProcessorTopologyInfo> {
965 if self.leaf_is_supported(EAX_PROCESSOR_TOPOLOGY_INFO) {
966 Some(ProcessorTopologyInfo::new(
967 self.read.cpuid1(EAX_PROCESSOR_TOPOLOGY_INFO),
968 ))
969 } else {
970 None
971 }
972 }
973
974 pub fn get_memory_encryption_info(&self) -> Option<MemoryEncryptionInfo> {
979 if self.leaf_is_supported(EAX_MEMORY_ENCRYPTION_INFO) {
980 Some(MemoryEncryptionInfo::new(
981 self.read.cpuid1(EAX_MEMORY_ENCRYPTION_INFO),
982 ))
983 } else {
984 None
985 }
986 }
987
988 pub fn get_pqos_extended_feature_info(&self) -> Option<PqosExtendedFeatureInfo<R>> {
993 if self.leaf_is_supported(EAX_PQOS_EXTENDED_FEATURES) {
994 Some(PqosExtendedFeatureInfo::new(self.read.clone()))
995 } else {
996 None
997 }
998 }
999
1000 pub fn get_extended_feature_identification_2(&self) -> Option<ExtendedFeatureIdentification2> {
1005 if self.leaf_is_supported(EAX_EXTENDED_FEATURE_IDENTIFICATION_2) {
1006 Some(ExtendedFeatureIdentification2::new(
1007 self.read.cpuid1(EAX_EXTENDED_FEATURE_IDENTIFICATION_2),
1008 ))
1009 } else {
1010 None
1011 }
1012 }
1013
1014 pub fn get_extended_performance_monitoring_and_debug(
1019 &self,
1020 ) -> Option<ExtendedPerformanceMonitoringDebug> {
1021 if self.leaf_is_supported(EAX_EXTENDED_PERFORMANCE_MONITORING_AND_DEBUG) {
1022 Some(ExtendedPerformanceMonitoringDebug::new(
1023 self.read
1024 .cpuid1(EAX_EXTENDED_PERFORMANCE_MONITORING_AND_DEBUG),
1025 ))
1026 } else {
1027 None
1028 }
1029 }
1030
1031 pub fn get_multi_key_encrypted_memory_capabilities(
1036 &self,
1037 ) -> Option<MultiKeyEncryptedMemoryCapabilities> {
1038 if self.leaf_is_supported(EAX_MULTI_KEY_ENCRYPTED_MEMORY_CAPABILITIES) {
1039 Some(MultiKeyEncryptedMemoryCapabilities::new(
1040 self.read
1041 .cpuid1(EAX_MULTI_KEY_ENCRYPTED_MEMORY_CAPABILITIES),
1042 ))
1043 } else {
1044 None
1045 }
1046 }
1047
1048 pub fn get_extended_cpu_topology(&self) -> Option<ExtendedCpuTopologyIter<R>> {
1053 if self.leaf_is_supported(EAX_EXTENDED_CPU_TOPOLOGY) {
1054 Some(ExtendedCpuTopologyIter::new(self.read.clone()))
1055 } else {
1056 None
1057 }
1058 }
1059}
1060
1061impl<R: CpuIdReader> Debug for CpuId<R> {
1062 fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
1063 f.debug_struct("CpuId")
1064 .field("vendor", &self.vendor)
1065 .field("vendor_info", &self.get_vendor_info())
1068 .field("feature_info", &self.get_feature_info())
1069 .field("cache_info", &self.get_cache_info())
1070 .field("processor_serial", &self.get_processor_serial())
1071 .field("cache_parameters", &self.get_cache_parameters())
1072 .field("monitor_mwait_info", &self.get_monitor_mwait_info())
1073 .field("thermal_power_info", &self.get_thermal_power_info())
1074 .field("extended_feature_info", &self.get_extended_feature_info())
1075 .field(
1076 "direct_cache_access_info",
1077 &self.get_direct_cache_access_info(),
1078 )
1079 .field(
1080 "performance_monitoring_info",
1081 &self.get_performance_monitoring_info(),
1082 )
1083 .field("extended_topology_info", &self.get_extended_topology_info())
1084 .field("extended_state_info", &self.get_extended_state_info())
1085 .field("rdt_monitoring_info", &self.get_rdt_monitoring_info())
1086 .field("rdt_allocation_info", &self.get_rdt_allocation_info())
1087 .field("sgx_info", &self.get_sgx_info())
1088 .field("processor_trace_info", &self.get_processor_trace_info())
1089 .field("tsc_info", &self.get_tsc_info())
1090 .field(
1091 "processor_frequency_info",
1092 &self.get_processor_frequency_info(),
1093 )
1094 .field(
1095 "deterministic_address_translation_info",
1096 &self.get_deterministic_address_translation_info(),
1097 )
1098 .field("soc_vendor_info", &self.get_soc_vendor_info())
1099 .field("hypervisor_info", &self.get_hypervisor_info())
1100 .field(
1101 "extended_processor_and_feature_identifiers",
1102 &self.get_extended_processor_and_feature_identifiers(),
1103 )
1104 .field("processor_brand_string", &self.get_processor_brand_string())
1105 .field("l1_cache_and_tlb_info", &self.get_l1_cache_and_tlb_info())
1106 .field(
1107 "l2_l3_cache_and_tlb_info",
1108 &self.get_l2_l3_cache_and_tlb_info(),
1109 )
1110 .field(
1111 "advanced_power_mgmt_info",
1112 &self.get_advanced_power_mgmt_info(),
1113 )
1114 .field(
1115 "processor_capacity_feature_info",
1116 &self.get_processor_capacity_feature_info(),
1117 )
1118 .field("svm_info", &self.get_svm_info())
1119 .field("tlb_1gb_page_info", &self.get_tlb_1gb_page_info())
1120 .field(
1121 "performance_optimization_info",
1122 &self.get_performance_optimization_info(),
1123 )
1124 .field(
1125 "processor_topology_info",
1126 &self.get_processor_topology_info(),
1127 )
1128 .field("memory_encryption_info", &self.get_memory_encryption_info())
1129 .finish()
1130 }
1131}
1132
1133#[derive(PartialEq, Eq)]
1145#[repr(C)]
1146pub struct VendorInfo {
1147 ebx: u32,
1148 edx: u32,
1149 ecx: u32,
1150}
1151
1152impl VendorInfo {
1153 pub fn as_str(&self) -> &str {
1155 let brand_string_start = self as *const VendorInfo as *const u8;
1156 let slice = unsafe {
1157 slice::from_raw_parts(brand_string_start, size_of::<VendorInfo>())
1160 };
1161
1162 str::from_utf8(slice).unwrap_or("InvalidVendorString")
1163 }
1164
1165 #[deprecated(
1166 since = "10.0.0",
1167 note = "Use idiomatic function name `as_str` instead"
1168 )]
1169 pub fn as_string(&self) -> &str {
1170 self.as_str()
1171 }
1172}
1173
1174impl Debug for VendorInfo {
1175 fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
1176 f.debug_struct("VendorInfo")
1177 .field("brand_string", &self.as_str())
1178 .finish()
1179 }
1180}
1181
1182impl fmt::Display for VendorInfo {
1183 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1184 write!(f, "{}", self.as_str())
1185 }
1186}
1187
1188#[derive(PartialEq, Eq, Clone)]
1196pub struct CacheInfoIter {
1197 current: u32,
1198 eax: u32,
1199 ebx: u32,
1200 ecx: u32,
1201 edx: u32,
1202}
1203
1204impl Iterator for CacheInfoIter {
1205 type Item = CacheInfo;
1206
1207 fn next(&mut self) -> Option<CacheInfo> {
1209 if self.current >= 4 * 4 {
1213 return None;
1214 }
1215 let reg_index = self.current % 4;
1216 let byte_index = self.current / 4;
1217
1218 let reg = match reg_index {
1219 0 => self.eax,
1220 1 => self.ebx,
1221 2 => self.ecx,
1222 3 => self.edx,
1223 _ => unreachable!(),
1224 };
1225
1226 let byte = match byte_index {
1227 0 => reg,
1228 1 => reg >> 8,
1229 2 => reg >> 16,
1230 3 => reg >> 24,
1231 _ => unreachable!(),
1232 } as u8;
1233
1234 if byte == 0 {
1235 self.current += 1;
1236 return self.next();
1237 }
1238
1239 for cache_info in CACHE_INFO_TABLE.iter() {
1240 if cache_info.num == byte {
1241 self.current += 1;
1242 return Some(*cache_info);
1243 }
1244 }
1245
1246 None
1247 }
1248}
1249
1250impl Debug for CacheInfoIter {
1251 fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
1252 let mut debug = f.debug_list();
1253 self.clone().for_each(|ref item| {
1254 debug.entry(item);
1255 });
1256 debug.finish()
1257 }
1258}
1259
1260#[derive(Copy, Clone, Debug)]
1262pub enum CacheInfoType {
1263 General,
1264 Cache,
1265 TLB,
1266 STLB,
1267 DTLB,
1268 Prefetch,
1269}
1270
1271#[derive(Copy, Clone)]
1273pub struct CacheInfo {
1274 pub num: u8,
1276 pub typ: CacheInfoType,
1278}
1279
1280impl CacheInfo {
1281 pub fn desc(&self) -> &'static str {
1283 match self.num {
1284 0x00 => "Null descriptor, this byte contains no information",
1285 0x01 => "Instruction TLB: 4 KByte pages, 4-way set associative, 32 entries",
1286 0x02 => "Instruction TLB: 4 MByte pages, fully associative, 2 entries",
1287 0x03 => "Data TLB: 4 KByte pages, 4-way set associative, 64 entries",
1288 0x04 => "Data TLB: 4 MByte pages, 4-way set associative, 8 entries",
1289 0x05 => "Data TLB1: 4 MByte pages, 4-way set associative, 32 entries",
1290 0x06 => "1st-level instruction cache: 8 KBytes, 4-way set associative, 32 byte line size",
1291 0x08 => "1st-level instruction cache: 16 KBytes, 4-way set associative, 32 byte line size",
1292 0x09 => "1st-level instruction cache: 32KBytes, 4-way set associative, 64 byte line size",
1293 0x0A => "1st-level data cache: 8 KBytes, 2-way set associative, 32 byte line size",
1294 0x0B => "Instruction TLB: 4 MByte pages, 4-way set associative, 4 entries",
1295 0x0C => "1st-level data cache: 16 KBytes, 4-way set associative, 32 byte line size",
1296 0x0D => "1st-level data cache: 16 KBytes, 4-way set associative, 64 byte line size",
1297 0x0E => "1st-level data cache: 24 KBytes, 6-way set associative, 64 byte line size",
1298 0x1D => "2nd-level cache: 128 KBytes, 2-way set associative, 64 byte line size",
1299 0x21 => "2nd-level cache: 256 KBytes, 8-way set associative, 64 byte line size",
1300 0x22 => "3rd-level cache: 512 KBytes, 4-way set associative, 64 byte line size, 2 lines per sector",
1301 0x23 => "3rd-level cache: 1 MBytes, 8-way set associative, 64 byte line size, 2 lines per sector",
1302 0x24 => "2nd-level cache: 1 MBytes, 16-way set associative, 64 byte line size",
1303 0x25 => "3rd-level cache: 2 MBytes, 8-way set associative, 64 byte line size, 2 lines per sector",
1304 0x29 => "3rd-level cache: 4 MBytes, 8-way set associative, 64 byte line size, 2 lines per sector",
1305 0x2C => "1st-level data cache: 32 KBytes, 8-way set associative, 64 byte line size",
1306 0x30 => "1st-level instruction cache: 32 KBytes, 8-way set associative, 64 byte line size",
1307 0x40 => "No 2nd-level cache or, if processor contains a valid 2nd-level cache, no 3rd-level cache",
1308 0x41 => "2nd-level cache: 128 KBytes, 4-way set associative, 32 byte line size",
1309 0x42 => "2nd-level cache: 256 KBytes, 4-way set associative, 32 byte line size",
1310 0x43 => "2nd-level cache: 512 KBytes, 4-way set associative, 32 byte line size",
1311 0x44 => "2nd-level cache: 1 MByte, 4-way set associative, 32 byte line size",
1312 0x45 => "2nd-level cache: 2 MByte, 4-way set associative, 32 byte line size",
1313 0x46 => "3rd-level cache: 4 MByte, 4-way set associative, 64 byte line size",
1314 0x47 => "3rd-level cache: 8 MByte, 8-way set associative, 64 byte line size",
1315 0x48 => "2nd-level cache: 3MByte, 12-way set associative, 64 byte line size",
1316 0x49 => "3rd-level cache: 4MB, 16-way set associative, 64-byte line size (Intel Xeon processor MP, Family 0FH, Model 06H); 2nd-level cache: 4 MByte, 16-way set ssociative, 64 byte line size",
1317 0x4A => "3rd-level cache: 6MByte, 12-way set associative, 64 byte line size",
1318 0x4B => "3rd-level cache: 8MByte, 16-way set associative, 64 byte line size",
1319 0x4C => "3rd-level cache: 12MByte, 12-way set associative, 64 byte line size",
1320 0x4D => "3rd-level cache: 16MByte, 16-way set associative, 64 byte line size",
1321 0x4E => "2nd-level cache: 6MByte, 24-way set associative, 64 byte line size",
1322 0x4F => "Instruction TLB: 4 KByte pages, 32 entries",
1323 0x50 => "Instruction TLB: 4 KByte and 2-MByte or 4-MByte pages, 64 entries",
1324 0x51 => "Instruction TLB: 4 KByte and 2-MByte or 4-MByte pages, 128 entries",
1325 0x52 => "Instruction TLB: 4 KByte and 2-MByte or 4-MByte pages, 256 entries",
1326 0x55 => "Instruction TLB: 2-MByte or 4-MByte pages, fully associative, 7 entries",
1327 0x56 => "Data TLB0: 4 MByte pages, 4-way set associative, 16 entries",
1328 0x57 => "Data TLB0: 4 KByte pages, 4-way associative, 16 entries",
1329 0x59 => "Data TLB0: 4 KByte pages, fully associative, 16 entries",
1330 0x5A => "Data TLB0: 2-MByte or 4 MByte pages, 4-way set associative, 32 entries",
1331 0x5B => "Data TLB: 4 KByte and 4 MByte pages, 64 entries",
1332 0x5C => "Data TLB: 4 KByte and 4 MByte pages,128 entries",
1333 0x5D => "Data TLB: 4 KByte and 4 MByte pages,256 entries",
1334 0x60 => "1st-level data cache: 16 KByte, 8-way set associative, 64 byte line size",
1335 0x61 => "Instruction TLB: 4 KByte pages, fully associative, 48 entries",
1336 0x63 => "Data TLB: 2 MByte or 4 MByte pages, 4-way set associative, 32 entries and a separate array with 1 GByte pages, 4-way set associative, 4 entries",
1337 0x64 => "Data TLB: 4 KByte pages, 4-way set associative, 512 entries",
1338 0x66 => "1st-level data cache: 8 KByte, 4-way set associative, 64 byte line size",
1339 0x67 => "1st-level data cache: 16 KByte, 4-way set associative, 64 byte line size",
1340 0x68 => "1st-level data cache: 32 KByte, 4-way set associative, 64 byte line size",
1341 0x6A => "uTLB: 4 KByte pages, 8-way set associative, 64 entries",
1342 0x6B => "DTLB: 4 KByte pages, 8-way set associative, 256 entries",
1343 0x6C => "DTLB: 2M/4M pages, 8-way set associative, 128 entries",
1344 0x6D => "DTLB: 1 GByte pages, fully associative, 16 entries",
1345 0x70 => "Trace cache: 12 K-μop, 8-way set associative",
1346 0x71 => "Trace cache: 16 K-μop, 8-way set associative",
1347 0x72 => "Trace cache: 32 K-μop, 8-way set associative",
1348 0x76 => "Instruction TLB: 2M/4M pages, fully associative, 8 entries",
1349 0x78 => "2nd-level cache: 1 MByte, 4-way set associative, 64byte line size",
1350 0x79 => "2nd-level cache: 128 KByte, 8-way set associative, 64 byte line size, 2 lines per sector",
1351 0x7A => "2nd-level cache: 256 KByte, 8-way set associative, 64 byte line size, 2 lines per sector",
1352 0x7B => "2nd-level cache: 512 KByte, 8-way set associative, 64 byte line size, 2 lines per sector",
1353 0x7C => "2nd-level cache: 1 MByte, 8-way set associative, 64 byte line size, 2 lines per sector",
1354 0x7D => "2nd-level cache: 2 MByte, 8-way set associative, 64byte line size",
1355 0x7F => "2nd-level cache: 512 KByte, 2-way set associative, 64-byte line size",
1356 0x80 => "2nd-level cache: 512 KByte, 8-way set associative, 64-byte line size",
1357 0x82 => "2nd-level cache: 256 KByte, 8-way set associative, 32 byte line size",
1358 0x83 => "2nd-level cache: 512 KByte, 8-way set associative, 32 byte line size",
1359 0x84 => "2nd-level cache: 1 MByte, 8-way set associative, 32 byte line size",
1360 0x85 => "2nd-level cache: 2 MByte, 8-way set associative, 32 byte line size",
1361 0x86 => "2nd-level cache: 512 KByte, 4-way set associative, 64 byte line size",
1362 0x87 => "2nd-level cache: 1 MByte, 8-way set associative, 64 byte line size",
1363 0xA0 => "DTLB: 4k pages, fully associative, 32 entries",
1364 0xB0 => "Instruction TLB: 4 KByte pages, 4-way set associative, 128 entries",
1365 0xB1 => "Instruction TLB: 2M pages, 4-way, 8 entries or 4M pages, 4-way, 4 entries",
1366 0xB2 => "Instruction TLB: 4KByte pages, 4-way set associative, 64 entries",
1367 0xB3 => "Data TLB: 4 KByte pages, 4-way set associative, 128 entries",
1368 0xB4 => "Data TLB1: 4 KByte pages, 4-way associative, 256 entries",
1369 0xB5 => "Instruction TLB: 4KByte pages, 8-way set associative, 64 entries",
1370 0xB6 => "Instruction TLB: 4KByte pages, 8-way set associative, 128 entries",
1371 0xBA => "Data TLB1: 4 KByte pages, 4-way associative, 64 entries",
1372 0xC0 => "Data TLB: 4 KByte and 4 MByte pages, 4-way associative, 8 entries",
1373 0xC1 => "Shared 2nd-Level TLB: 4 KByte/2MByte pages, 8-way associative, 1024 entries",
1374 0xC2 => "DTLB: 2 MByte/$MByte pages, 4-way associative, 16 entries",
1375 0xC3 => "Shared 2nd-Level TLB: 4 KByte /2 MByte pages, 6-way associative, 1536 entries. Also 1GBbyte pages, 4-way, 16 entries.",
1376 0xC4 => "DTLB: 2M/4M Byte pages, 4-way associative, 32 entries",
1377 0xCA => "Shared 2nd-Level TLB: 4 KByte pages, 4-way associative, 512 entries",
1378 0xD0 => "3rd-level cache: 512 KByte, 4-way set associative, 64 byte line size",
1379 0xD1 => "3rd-level cache: 1 MByte, 4-way set associative, 64 byte line size",
1380 0xD2 => "3rd-level cache: 2 MByte, 4-way set associative, 64 byte line size",
1381 0xD6 => "3rd-level cache: 1 MByte, 8-way set associative, 64 byte line size",
1382 0xD7 => "3rd-level cache: 2 MByte, 8-way set associative, 64 byte line size",
1383 0xD8 => "3rd-level cache: 4 MByte, 8-way set associative, 64 byte line size",
1384 0xDC => "3rd-level cache: 1.5 MByte, 12-way set associative, 64 byte line size",
1385 0xDD => "3rd-level cache: 3 MByte, 12-way set associative, 64 byte line size",
1386 0xDE => "3rd-level cache: 6 MByte, 12-way set associative, 64 byte line size",
1387 0xE2 => "3rd-level cache: 2 MByte, 16-way set associative, 64 byte line size",
1388 0xE3 => "3rd-level cache: 4 MByte, 16-way set associative, 64 byte line size",
1389 0xE4 => "3rd-level cache: 8 MByte, 16-way set associative, 64 byte line size",
1390 0xEA => "3rd-level cache: 12MByte, 24-way set associative, 64 byte line size",
1391 0xEB => "3rd-level cache: 18MByte, 24-way set associative, 64 byte line size",
1392 0xEC => "3rd-level cache: 24MByte, 24-way set associative, 64 byte line size",
1393 0xF0 => "64-Byte prefetching",
1394 0xF1 => "128-Byte prefetching",
1395 0xFE => "CPUID leaf 2 does not report TLB descriptor information; use CPUID leaf 18H to query TLB and other address translation parameters.",
1396 0xFF => "CPUID leaf 2 does not report cache descriptor information, use CPUID leaf 4 to query cache parameters",
1397 _ => "Unknown cache type!"
1398 }
1399 }
1400}
1401
1402impl Debug for CacheInfo {
1403 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
1404 f.debug_struct("CacheInfo")
1405 .field("typ", &self.typ)
1406 .field("desc", &self.desc())
1407 .finish()
1408 }
1409}
1410
1411impl fmt::Display for CacheInfo {
1412 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1413 let typ = match self.typ {
1414 CacheInfoType::General => "N/A",
1415 CacheInfoType::Cache => "Cache",
1416 CacheInfoType::TLB => "TLB",
1417 CacheInfoType::STLB => "STLB",
1418 CacheInfoType::DTLB => "DTLB",
1419 CacheInfoType::Prefetch => "Prefetcher",
1420 };
1421
1422 write!(f, "{:x}:\t {}: {}", self.num, typ, self.desc())
1423 }
1424}
1425
1426pub const CACHE_INFO_TABLE: [CacheInfo; 108] = [
1428 CacheInfo {
1429 num: 0x00,
1430 typ: CacheInfoType::General,
1431 },
1432 CacheInfo {
1433 num: 0x01,
1434 typ: CacheInfoType::TLB,
1435 },
1436 CacheInfo {
1437 num: 0x02,
1438 typ: CacheInfoType::TLB,
1439 },
1440 CacheInfo {
1441 num: 0x03,
1442 typ: CacheInfoType::TLB,
1443 },
1444 CacheInfo {
1445 num: 0x04,
1446 typ: CacheInfoType::TLB,
1447 },
1448 CacheInfo {
1449 num: 0x05,
1450 typ: CacheInfoType::TLB,
1451 },
1452 CacheInfo {
1453 num: 0x06,
1454 typ: CacheInfoType::Cache,
1455 },
1456 CacheInfo {
1457 num: 0x08,
1458 typ: CacheInfoType::Cache,
1459 },
1460 CacheInfo {
1461 num: 0x09,
1462 typ: CacheInfoType::Cache,
1463 },
1464 CacheInfo {
1465 num: 0x0A,
1466 typ: CacheInfoType::Cache,
1467 },
1468 CacheInfo {
1469 num: 0x0B,
1470 typ: CacheInfoType::TLB,
1471 },
1472 CacheInfo {
1473 num: 0x0C,
1474 typ: CacheInfoType::Cache,
1475 },
1476 CacheInfo {
1477 num: 0x0D,
1478 typ: CacheInfoType::Cache,
1479 },
1480 CacheInfo {
1481 num: 0x0E,
1482 typ: CacheInfoType::Cache,
1483 },
1484 CacheInfo {
1485 num: 0x21,
1486 typ: CacheInfoType::Cache,
1487 },
1488 CacheInfo {
1489 num: 0x22,
1490 typ: CacheInfoType::Cache,
1491 },
1492 CacheInfo {
1493 num: 0x23,
1494 typ: CacheInfoType::Cache,
1495 },
1496 CacheInfo {
1497 num: 0x24,
1498 typ: CacheInfoType::Cache,
1499 },
1500 CacheInfo {
1501 num: 0x25,
1502 typ: CacheInfoType::Cache,
1503 },
1504 CacheInfo {
1505 num: 0x29,
1506 typ: CacheInfoType::Cache,
1507 },
1508 CacheInfo {
1509 num: 0x2C,
1510 typ: CacheInfoType::Cache,
1511 },
1512 CacheInfo {
1513 num: 0x30,
1514 typ: CacheInfoType::Cache,
1515 },
1516 CacheInfo {
1517 num: 0x40,
1518 typ: CacheInfoType::Cache,
1519 },
1520 CacheInfo {
1521 num: 0x41,
1522 typ: CacheInfoType::Cache,
1523 },
1524 CacheInfo {
1525 num: 0x42,
1526 typ: CacheInfoType::Cache,
1527 },
1528 CacheInfo {
1529 num: 0x43,
1530 typ: CacheInfoType::Cache,
1531 },
1532 CacheInfo {
1533 num: 0x44,
1534 typ: CacheInfoType::Cache,
1535 },
1536 CacheInfo {
1537 num: 0x45,
1538 typ: CacheInfoType::Cache,
1539 },
1540 CacheInfo {
1541 num: 0x46,
1542 typ: CacheInfoType::Cache,
1543 },
1544 CacheInfo {
1545 num: 0x47,
1546 typ: CacheInfoType::Cache,
1547 },
1548 CacheInfo {
1549 num: 0x48,
1550 typ: CacheInfoType::Cache,
1551 },
1552 CacheInfo {
1553 num: 0x49,
1554 typ: CacheInfoType::Cache,
1555 },
1556 CacheInfo {
1557 num: 0x4A,
1558 typ: CacheInfoType::Cache,
1559 },
1560 CacheInfo {
1561 num: 0x4B,
1562 typ: CacheInfoType::Cache,
1563 },
1564 CacheInfo {
1565 num: 0x4C,
1566 typ: CacheInfoType::Cache,
1567 },
1568 CacheInfo {
1569 num: 0x4D,
1570 typ: CacheInfoType::Cache,
1571 },
1572 CacheInfo {
1573 num: 0x4E,
1574 typ: CacheInfoType::Cache,
1575 },
1576 CacheInfo {
1577 num: 0x4F,
1578 typ: CacheInfoType::TLB,
1579 },
1580 CacheInfo {
1581 num: 0x50,
1582 typ: CacheInfoType::TLB,
1583 },
1584 CacheInfo {
1585 num: 0x51,
1586 typ: CacheInfoType::TLB,
1587 },
1588 CacheInfo {
1589 num: 0x52,
1590 typ: CacheInfoType::TLB,
1591 },
1592 CacheInfo {
1593 num: 0x55,
1594 typ: CacheInfoType::TLB,
1595 },
1596 CacheInfo {
1597 num: 0x56,
1598 typ: CacheInfoType::TLB,
1599 },
1600 CacheInfo {
1601 num: 0x57,
1602 typ: CacheInfoType::TLB,
1603 },
1604 CacheInfo {
1605 num: 0x59,
1606 typ: CacheInfoType::TLB,
1607 },
1608 CacheInfo {
1609 num: 0x5A,
1610 typ: CacheInfoType::TLB,
1611 },
1612 CacheInfo {
1613 num: 0x5B,
1614 typ: CacheInfoType::TLB,
1615 },
1616 CacheInfo {
1617 num: 0x5C,
1618 typ: CacheInfoType::TLB,
1619 },
1620 CacheInfo {
1621 num: 0x5D,
1622 typ: CacheInfoType::TLB,
1623 },
1624 CacheInfo {
1625 num: 0x60,
1626 typ: CacheInfoType::Cache,
1627 },
1628 CacheInfo {
1629 num: 0x61,
1630 typ: CacheInfoType::TLB,
1631 },
1632 CacheInfo {
1633 num: 0x63,
1634 typ: CacheInfoType::TLB,
1635 },
1636 CacheInfo {
1637 num: 0x66,
1638 typ: CacheInfoType::Cache,
1639 },
1640 CacheInfo {
1641 num: 0x67,
1642 typ: CacheInfoType::Cache,
1643 },
1644 CacheInfo {
1645 num: 0x68,
1646 typ: CacheInfoType::Cache,
1647 },
1648 CacheInfo {
1649 num: 0x6A,
1650 typ: CacheInfoType::Cache,
1651 },
1652 CacheInfo {
1653 num: 0x6B,
1654 typ: CacheInfoType::Cache,
1655 },
1656 CacheInfo {
1657 num: 0x6C,
1658 typ: CacheInfoType::Cache,
1659 },
1660 CacheInfo {
1661 num: 0x6D,
1662 typ: CacheInfoType::Cache,
1663 },
1664 CacheInfo {
1665 num: 0x70,
1666 typ: CacheInfoType::Cache,
1667 },
1668 CacheInfo {
1669 num: 0x71,
1670 typ: CacheInfoType::Cache,
1671 },
1672 CacheInfo {
1673 num: 0x72,
1674 typ: CacheInfoType::Cache,
1675 },
1676 CacheInfo {
1677 num: 0x76,
1678 typ: CacheInfoType::TLB,
1679 },
1680 CacheInfo {
1681 num: 0x78,
1682 typ: CacheInfoType::Cache,
1683 },
1684 CacheInfo {
1685 num: 0x79,
1686 typ: CacheInfoType::Cache,
1687 },
1688 CacheInfo {
1689 num: 0x7A,
1690 typ: CacheInfoType::Cache,
1691 },
1692 CacheInfo {
1693 num: 0x7B,
1694 typ: CacheInfoType::Cache,
1695 },
1696 CacheInfo {
1697 num: 0x7C,
1698 typ: CacheInfoType::Cache,
1699 },
1700 CacheInfo {
1701 num: 0x7D,
1702 typ: CacheInfoType::Cache,
1703 },
1704 CacheInfo {
1705 num: 0x7F,
1706 typ: CacheInfoType::Cache,
1707 },
1708 CacheInfo {
1709 num: 0x80,
1710 typ: CacheInfoType::Cache,
1711 },
1712 CacheInfo {
1713 num: 0x82,
1714 typ: CacheInfoType::Cache,
1715 },
1716 CacheInfo {
1717 num: 0x83,
1718 typ: CacheInfoType::Cache,
1719 },
1720 CacheInfo {
1721 num: 0x84,
1722 typ: CacheInfoType::Cache,
1723 },
1724 CacheInfo {
1725 num: 0x85,
1726 typ: CacheInfoType::Cache,
1727 },
1728 CacheInfo {
1729 num: 0x86,
1730 typ: CacheInfoType::Cache,
1731 },
1732 CacheInfo {
1733 num: 0x87,
1734 typ: CacheInfoType::Cache,
1735 },
1736 CacheInfo {
1737 num: 0xB0,
1738 typ: CacheInfoType::TLB,
1739 },
1740 CacheInfo {
1741 num: 0xB1,
1742 typ: CacheInfoType::TLB,
1743 },
1744 CacheInfo {
1745 num: 0xB2,
1746 typ: CacheInfoType::TLB,
1747 },
1748 CacheInfo {
1749 num: 0xB3,
1750 typ: CacheInfoType::TLB,
1751 },
1752 CacheInfo {
1753 num: 0xB4,
1754 typ: CacheInfoType::TLB,
1755 },
1756 CacheInfo {
1757 num: 0xB5,
1758 typ: CacheInfoType::TLB,
1759 },
1760 CacheInfo {
1761 num: 0xB6,
1762 typ: CacheInfoType::TLB,
1763 },
1764 CacheInfo {
1765 num: 0xBA,
1766 typ: CacheInfoType::TLB,
1767 },
1768 CacheInfo {
1769 num: 0xC0,
1770 typ: CacheInfoType::TLB,
1771 },
1772 CacheInfo {
1773 num: 0xC1,
1774 typ: CacheInfoType::STLB,
1775 },
1776 CacheInfo {
1777 num: 0xC2,
1778 typ: CacheInfoType::DTLB,
1779 },
1780 CacheInfo {
1781 num: 0xCA,
1782 typ: CacheInfoType::STLB,
1783 },
1784 CacheInfo {
1785 num: 0xD0,
1786 typ: CacheInfoType::Cache,
1787 },
1788 CacheInfo {
1789 num: 0xD1,
1790 typ: CacheInfoType::Cache,
1791 },
1792 CacheInfo {
1793 num: 0xD2,
1794 typ: CacheInfoType::Cache,
1795 },
1796 CacheInfo {
1797 num: 0xD6,
1798 typ: CacheInfoType::Cache,
1799 },
1800 CacheInfo {
1801 num: 0xD7,
1802 typ: CacheInfoType::Cache,
1803 },
1804 CacheInfo {
1805 num: 0xD8,
1806 typ: CacheInfoType::Cache,
1807 },
1808 CacheInfo {
1809 num: 0xDC,
1810 typ: CacheInfoType::Cache,
1811 },
1812 CacheInfo {
1813 num: 0xDD,
1814 typ: CacheInfoType::Cache,
1815 },
1816 CacheInfo {
1817 num: 0xDE,
1818 typ: CacheInfoType::Cache,
1819 },
1820 CacheInfo {
1821 num: 0xE2,
1822 typ: CacheInfoType::Cache,
1823 },
1824 CacheInfo {
1825 num: 0xE3,
1826 typ: CacheInfoType::Cache,
1827 },
1828 CacheInfo {
1829 num: 0xE4,
1830 typ: CacheInfoType::Cache,
1831 },
1832 CacheInfo {
1833 num: 0xEA,
1834 typ: CacheInfoType::Cache,
1835 },
1836 CacheInfo {
1837 num: 0xEB,
1838 typ: CacheInfoType::Cache,
1839 },
1840 CacheInfo {
1841 num: 0xEC,
1842 typ: CacheInfoType::Cache,
1843 },
1844 CacheInfo {
1845 num: 0xF0,
1846 typ: CacheInfoType::Prefetch,
1847 },
1848 CacheInfo {
1849 num: 0xF1,
1850 typ: CacheInfoType::Prefetch,
1851 },
1852 CacheInfo {
1853 num: 0xFE,
1854 typ: CacheInfoType::General,
1855 },
1856 CacheInfo {
1857 num: 0xFF,
1858 typ: CacheInfoType::General,
1859 },
1860];
1861
1862#[derive(PartialEq, Eq)]
1873pub struct ProcessorSerial {
1874 ecx: u32,
1876 edx: u32,
1878 eax: u32,
1880}
1881
1882impl ProcessorSerial {
1883 pub fn serial_lower(&self) -> u32 {
1887 self.ecx
1888 }
1889
1890 pub fn serial_middle(&self) -> u32 {
1894 self.edx
1895 }
1896
1897 pub fn serial_upper(&self) -> u32 {
1899 self.eax
1900 }
1901
1902 pub fn serial(&self) -> u64 {
1904 (self.serial_lower() as u64) | (self.serial_middle() as u64) << 32
1905 }
1906
1907 pub fn serial_all(&self) -> u128 {
1909 (self.serial_lower() as u128)
1910 | ((self.serial_middle() as u128) << 32)
1911 | ((self.serial_upper() as u128) << 64)
1912 }
1913}
1914
1915impl Debug for ProcessorSerial {
1916 fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
1917 f.debug_struct("ProcessorSerial")
1918 .field("serial_lower", &self.serial_lower())
1919 .field("serial_middle", &self.serial_middle())
1920 .finish()
1921 }
1922}
1923
1924pub struct FeatureInfo {
1929 vendor: Vendor,
1930 eax: u32,
1931 ebx: u32,
1932 edx_ecx: FeatureInfoFlags,
1933}
1934
1935impl FeatureInfo {
1936 pub fn extended_family_id(&self) -> u8 {
1938 get_bits(self.eax, 20, 27) as u8
1939 }
1940
1941 pub fn extended_model_id(&self) -> u8 {
1943 get_bits(self.eax, 16, 19) as u8
1944 }
1945
1946 pub fn base_family_id(&self) -> u8 {
1948 get_bits(self.eax, 8, 11) as u8
1949 }
1950
1951 pub fn base_model_id(&self) -> u8 {
1953 get_bits(self.eax, 4, 7) as u8
1954 }
1955
1956 pub fn family_id(&self) -> u8 {
1957 let base_family_id = self.base_family_id();
1958 let extended_family_id = self.extended_family_id();
1959 let just_use_base = (self.vendor == Vendor::Amd && base_family_id < 0xf)
1960 || (self.vendor == Vendor::Intel && base_family_id != 0xf);
1961
1962 if just_use_base {
1963 base_family_id
1964 } else {
1965 base_family_id + extended_family_id
1966 }
1967 }
1968
1969 pub fn model_id(&self) -> u8 {
1970 let base_family_id = self.base_family_id();
1971 let base_model_id = self.base_model_id();
1972 let extended_model_id = self.extended_model_id();
1973 let just_use_base = (self.vendor == Vendor::Amd && base_family_id < 0xf)
1974 || (self.vendor == Vendor::Intel && base_family_id != 0xf && base_family_id != 0x6);
1975
1976 if just_use_base {
1977 base_model_id
1978 } else {
1979 (extended_model_id << 4) | base_model_id
1980 }
1981 }
1982
1983 pub fn stepping_id(&self) -> u8 {
1985 get_bits(self.eax, 0, 3) as u8
1986 }
1987
1988 pub fn brand_index(&self) -> u8 {
1990 get_bits(self.ebx, 0, 7) as u8
1991 }
1992
1993 pub fn cflush_cache_line_size(&self) -> u8 {
1995 get_bits(self.ebx, 8, 15) as u8
1996 }
1997
1998 pub fn initial_local_apic_id(&self) -> u8 {
2000 get_bits(self.ebx, 24, 31) as u8
2001 }
2002
2003 pub fn max_logical_processor_ids(&self) -> u8 {
2005 get_bits(self.ebx, 16, 23) as u8
2006 }
2007
2008 check_flag!(
2009 doc = "Streaming SIMD Extensions 3 (SSE3). A value of 1 indicates the processor \
2010 supports this technology.",
2011 has_sse3,
2012 edx_ecx,
2013 FeatureInfoFlags::SSE3
2014 );
2015
2016 check_flag!(
2017 doc = "PCLMULQDQ. A value of 1 indicates the processor supports the PCLMULQDQ \
2018 instruction",
2019 has_pclmulqdq,
2020 edx_ecx,
2021 FeatureInfoFlags::PCLMULQDQ
2022 );
2023
2024 check_flag!(
2025 doc = "64-bit DS Area. A value of 1 indicates the processor supports DS area \
2026 using 64-bit layout",
2027 has_ds_area,
2028 edx_ecx,
2029 FeatureInfoFlags::DTES64
2030 );
2031
2032 check_flag!(
2033 doc = "MONITOR/MWAIT. A value of 1 indicates the processor supports this feature.",
2034 has_monitor_mwait,
2035 edx_ecx,
2036 FeatureInfoFlags::MONITOR
2037 );
2038
2039 check_flag!(
2040 doc = "CPL Qualified Debug Store. A value of 1 indicates the processor supports \
2041 the extensions to the Debug Store feature to allow for branch message \
2042 storage qualified by CPL.",
2043 has_cpl,
2044 edx_ecx,
2045 FeatureInfoFlags::DSCPL
2046 );
2047
2048 check_flag!(
2049 doc = "Virtual Machine Extensions. A value of 1 indicates that the processor \
2050 supports this technology.",
2051 has_vmx,
2052 edx_ecx,
2053 FeatureInfoFlags::VMX
2054 );
2055
2056 check_flag!(
2057 doc = "Safer Mode Extensions. A value of 1 indicates that the processor supports \
2058 this technology. See Chapter 5, Safer Mode Extensions Reference.",
2059 has_smx,
2060 edx_ecx,
2061 FeatureInfoFlags::SMX
2062 );
2063
2064 check_flag!(
2065 doc = "Enhanced Intel SpeedStep® technology. A value of 1 indicates that the \
2066 processor supports this technology.",
2067 has_eist,
2068 edx_ecx,
2069 FeatureInfoFlags::EIST
2070 );
2071
2072 check_flag!(
2073 doc = "Thermal Monitor 2. A value of 1 indicates whether the processor supports \
2074 this technology.",
2075 has_tm2,
2076 edx_ecx,
2077 FeatureInfoFlags::TM2
2078 );
2079
2080 check_flag!(
2081 doc = "A value of 1 indicates the presence of the Supplemental Streaming SIMD \
2082 Extensions 3 (SSSE3). A value of 0 indicates the instruction extensions \
2083 are not present in the processor",
2084 has_ssse3,
2085 edx_ecx,
2086 FeatureInfoFlags::SSSE3
2087 );
2088
2089 check_flag!(
2090 doc = "L1 Context ID. A value of 1 indicates the L1 data cache mode can be set \
2091 to either adaptive mode or shared mode. A value of 0 indicates this \
2092 feature is not supported. See definition of the IA32_MISC_ENABLE MSR Bit \
2093 24 (L1 Data Cache Context Mode) for details.",
2094 has_cnxtid,
2095 edx_ecx,
2096 FeatureInfoFlags::CNXTID
2097 );
2098
2099 check_flag!(
2100 doc = "A value of 1 indicates the processor supports FMA extensions using YMM \
2101 state.",
2102 has_fma,
2103 edx_ecx,
2104 FeatureInfoFlags::FMA
2105 );
2106
2107 check_flag!(
2108 doc = "CMPXCHG16B Available. A value of 1 indicates that the feature is \
2109 available. See the CMPXCHG8B/CMPXCHG16B Compare and Exchange Bytes \
2110 section. 14",
2111 has_cmpxchg16b,
2112 edx_ecx,
2113 FeatureInfoFlags::CMPXCHG16B
2114 );
2115
2116 check_flag!(
2117 doc = "Perfmon and Debug Capability: A value of 1 indicates the processor \
2118 supports the performance and debug feature indication MSR \
2119 IA32_PERF_CAPABILITIES.",
2120 has_pdcm,
2121 edx_ecx,
2122 FeatureInfoFlags::PDCM
2123 );
2124
2125 check_flag!(
2126 doc = "Process-context identifiers. A value of 1 indicates that the processor \
2127 supports PCIDs and the software may set CR4.PCIDE to 1.",
2128 has_pcid,
2129 edx_ecx,
2130 FeatureInfoFlags::PCID
2131 );
2132
2133 check_flag!(
2134 doc = "A value of 1 indicates the processor supports the ability to prefetch \
2135 data from a memory mapped device.",
2136 has_dca,
2137 edx_ecx,
2138 FeatureInfoFlags::DCA
2139 );
2140
2141 check_flag!(
2142 doc = "A value of 1 indicates that the processor supports SSE4.1.",
2143 has_sse41,
2144 edx_ecx,
2145 FeatureInfoFlags::SSE41
2146 );
2147
2148 check_flag!(
2149 doc = "A value of 1 indicates that the processor supports SSE4.2.",
2150 has_sse42,
2151 edx_ecx,
2152 FeatureInfoFlags::SSE42
2153 );
2154
2155 check_flag!(
2156 doc = "A value of 1 indicates that the processor supports x2APIC feature.",
2157 has_x2apic,
2158 edx_ecx,
2159 FeatureInfoFlags::X2APIC
2160 );
2161
2162 check_flag!(
2163 doc = "A value of 1 indicates that the processor supports MOVBE instruction.",
2164 has_movbe,
2165 edx_ecx,
2166 FeatureInfoFlags::MOVBE
2167 );
2168
2169 check_flag!(
2170 doc = "A value of 1 indicates that the processor supports the POPCNT instruction.",
2171 has_popcnt,
2172 edx_ecx,
2173 FeatureInfoFlags::POPCNT
2174 );
2175
2176 check_flag!(
2177 doc = "A value of 1 indicates that the processors local APIC timer supports \
2178 one-shot operation using a TSC deadline value.",
2179 has_tsc_deadline,
2180 edx_ecx,
2181 FeatureInfoFlags::TSC_DEADLINE
2182 );
2183
2184 check_flag!(
2185 doc = "A value of 1 indicates that the processor supports the AESNI instruction \
2186 extensions.",
2187 has_aesni,
2188 edx_ecx,
2189 FeatureInfoFlags::AESNI
2190 );
2191
2192 check_flag!(
2193 doc = "A value of 1 indicates that the processor supports the XSAVE/XRSTOR \
2194 processor extended states feature, the XSETBV/XGETBV instructions, and \
2195 XCR0.",
2196 has_xsave,
2197 edx_ecx,
2198 FeatureInfoFlags::XSAVE
2199 );
2200
2201 check_flag!(
2202 doc = "A value of 1 indicates that the OS has enabled XSETBV/XGETBV instructions \
2203 to access XCR0, and support for processor extended state management using \
2204 XSAVE/XRSTOR.",
2205 has_oxsave,
2206 edx_ecx,
2207 FeatureInfoFlags::OSXSAVE
2208 );
2209
2210 check_flag!(
2211 doc = "A value of 1 indicates the processor supports the AVX instruction \
2212 extensions.",
2213 has_avx,
2214 edx_ecx,
2215 FeatureInfoFlags::AVX
2216 );
2217
2218 check_flag!(
2219 doc = "A value of 1 indicates that processor supports 16-bit floating-point \
2220 conversion instructions.",
2221 has_f16c,
2222 edx_ecx,
2223 FeatureInfoFlags::F16C
2224 );
2225
2226 check_flag!(
2227 doc = "A value of 1 indicates that processor supports RDRAND instruction.",
2228 has_rdrand,
2229 edx_ecx,
2230 FeatureInfoFlags::RDRAND
2231 );
2232
2233 check_flag!(
2234 doc = "A value of 1 indicates the indicates the presence of a hypervisor.",
2235 has_hypervisor,
2236 edx_ecx,
2237 FeatureInfoFlags::HYPERVISOR
2238 );
2239
2240 check_flag!(
2241 doc = "Floating Point Unit On-Chip. The processor contains an x87 FPU.",
2242 has_fpu,
2243 edx_ecx,
2244 FeatureInfoFlags::FPU
2245 );
2246
2247 check_flag!(
2248 doc = "Virtual 8086 Mode Enhancements. Virtual 8086 mode enhancements, including \
2249 CR4.VME for controlling the feature, CR4.PVI for protected mode virtual \
2250 interrupts, software interrupt indirection, expansion of the TSS with the \
2251 software indirection bitmap, and EFLAGS.VIF and EFLAGS.VIP flags.",
2252 has_vme,
2253 edx_ecx,
2254 FeatureInfoFlags::VME
2255 );
2256
2257 check_flag!(
2258 doc = "Debugging Extensions. Support for I/O breakpoints, including CR4.DE for \
2259 controlling the feature, and optional trapping of accesses to DR4 and DR5.",
2260 has_de,
2261 edx_ecx,
2262 FeatureInfoFlags::DE
2263 );
2264
2265 check_flag!(
2266 doc = "Page Size Extension. Large pages of size 4 MByte are supported, including \
2267 CR4.PSE for controlling the feature, the defined dirty bit in PDE (Page \
2268 Directory Entries), optional reserved bit trapping in CR3, PDEs, and PTEs.",
2269 has_pse,
2270 edx_ecx,
2271 FeatureInfoFlags::PSE
2272 );
2273
2274 check_flag!(
2275 doc = "Time Stamp Counter. The RDTSC instruction is supported, including CR4.TSD \
2276 for controlling privilege.",
2277 has_tsc,
2278 edx_ecx,
2279 FeatureInfoFlags::TSC
2280 );
2281
2282 check_flag!(
2283 doc = "Model Specific Registers RDMSR and WRMSR Instructions. The RDMSR and \
2284 WRMSR instructions are supported. Some of the MSRs are implementation \
2285 dependent.",
2286 has_msr,
2287 edx_ecx,
2288 FeatureInfoFlags::MSR
2289 );
2290
2291 check_flag!(
2292 doc = "Physical Address Extension. Physical addresses greater than 32 bits are \
2293 supported: extended page table entry formats, an extra level in the page \
2294 translation tables is defined, 2-MByte pages are supported instead of 4 \
2295 Mbyte pages if PAE bit is 1.",
2296 has_pae,
2297 edx_ecx,
2298 FeatureInfoFlags::PAE
2299 );
2300
2301 check_flag!(
2302 doc = "Machine Check Exception. Exception 18 is defined for Machine Checks, \
2303 including CR4.MCE for controlling the feature. This feature does not \
2304 define the model-specific implementations of machine-check error logging, \
2305 reporting, and processor shutdowns. Machine Check exception handlers may \
2306 have to depend on processor version to do model specific processing of \
2307 the exception, or test for the presence of the Machine Check feature.",
2308 has_mce,
2309 edx_ecx,
2310 FeatureInfoFlags::MCE
2311 );
2312
2313 check_flag!(
2314 doc = "CMPXCHG8B Instruction. The compare-and-exchange 8 bytes (64 bits) \
2315 instruction is supported (implicitly locked and atomic).",
2316 has_cmpxchg8b,
2317 edx_ecx,
2318 FeatureInfoFlags::CX8
2319 );
2320
2321 check_flag!(
2322 doc = "APIC On-Chip. The processor contains an Advanced Programmable Interrupt \
2323 Controller (APIC), responding to memory mapped commands in the physical \
2324 address range FFFE0000H to FFFE0FFFH (by default - some processors permit \
2325 the APIC to be relocated).",
2326 has_apic,
2327 edx_ecx,
2328 FeatureInfoFlags::APIC
2329 );
2330
2331 check_flag!(
2332 doc = "SYSENTER and SYSEXIT Instructions. The SYSENTER and SYSEXIT and \
2333 associated MSRs are supported.",
2334 has_sysenter_sysexit,
2335 edx_ecx,
2336 FeatureInfoFlags::SEP
2337 );
2338
2339 check_flag!(
2340 doc = "Memory Type Range Registers. MTRRs are supported. The MTRRcap MSR \
2341 contains feature bits that describe what memory types are supported, how \
2342 many variable MTRRs are supported, and whether fixed MTRRs are supported.",
2343 has_mtrr,
2344 edx_ecx,
2345 FeatureInfoFlags::MTRR
2346 );
2347
2348 check_flag!(
2349 doc = "Page Global Bit. The global bit is supported in paging-structure entries \
2350 that map a page, indicating TLB entries that are common to different \
2351 processes and need not be flushed. The CR4.PGE bit controls this feature.",
2352 has_pge,
2353 edx_ecx,
2354 FeatureInfoFlags::PGE
2355 );
2356
2357 check_flag!(
2358 doc = "Machine Check Architecture. A value of 1 indicates the Machine Check \
2359 Architecture of reporting machine errors is supported. The MCG_CAP MSR \
2360 contains feature bits describing how many banks of error reporting MSRs \
2361 are supported.",
2362 has_mca,
2363 edx_ecx,
2364 FeatureInfoFlags::MCA
2365 );
2366
2367 check_flag!(
2368 doc = "Conditional Move Instructions. The conditional move instruction CMOV is \
2369 supported. In addition, if x87 FPU is present as indicated by the \
2370 CPUID.FPU feature bit, then the FCOMI and FCMOV instructions are supported",
2371 has_cmov,
2372 edx_ecx,
2373 FeatureInfoFlags::CMOV
2374 );
2375
2376 check_flag!(
2377 doc = "Page Attribute Table. Page Attribute Table is supported. This feature \
2378 augments the Memory Type Range Registers (MTRRs), allowing an operating \
2379 system to specify attributes of memory accessed through a linear address \
2380 on a 4KB granularity.",
2381 has_pat,
2382 edx_ecx,
2383 FeatureInfoFlags::PAT
2384 );
2385
2386 check_flag!(
2387 doc = "36-Bit Page Size Extension. 4-MByte pages addressing physical memory \
2388 beyond 4 GBytes are supported with 32-bit paging. This feature indicates \
2389 that upper bits of the physical address of a 4-MByte page are encoded in \
2390 bits 20:13 of the page-directory entry. Such physical addresses are \
2391 limited by MAXPHYADDR and may be up to 40 bits in size.",
2392 has_pse36,
2393 edx_ecx,
2394 FeatureInfoFlags::PSE36
2395 );
2396
2397 check_flag!(
2398 doc = "Processor Serial Number. The processor supports the 96-bit processor \
2399 identification number feature and the feature is enabled.",
2400 has_psn,
2401 edx_ecx,
2402 FeatureInfoFlags::PSN
2403 );
2404
2405 check_flag!(
2406 doc = "CLFLUSH Instruction. CLFLUSH Instruction is supported.",
2407 has_clflush,
2408 edx_ecx,
2409 FeatureInfoFlags::CLFSH
2410 );
2411
2412 check_flag!(
2413 doc = "Debug Store. The processor supports the ability to write debug \
2414 information into a memory resident buffer. This feature is used by the \
2415 branch trace store (BTS) and processor event-based sampling (PEBS) \
2416 facilities (see Chapter 23, Introduction to Virtual-Machine Extensions, \
2417 in the Intel® 64 and IA-32 Architectures Software Developers Manual, \
2418 Volume 3C).",
2419 has_ds,
2420 edx_ecx,
2421 FeatureInfoFlags::DS
2422 );
2423
2424 check_flag!(
2425 doc = "Thermal Monitor and Software Controlled Clock Facilities. The processor \
2426 implements internal MSRs that allow processor temperature to be monitored \
2427 and processor performance to be modulated in predefined duty cycles under \
2428 software control.",
2429 has_acpi,
2430 edx_ecx,
2431 FeatureInfoFlags::ACPI
2432 );
2433
2434 check_flag!(
2435 doc = "Intel MMX Technology. The processor supports the Intel MMX technology.",
2436 has_mmx,
2437 edx_ecx,
2438 FeatureInfoFlags::MMX
2439 );
2440
2441 check_flag!(
2442 doc = "FXSAVE and FXRSTOR Instructions. The FXSAVE and FXRSTOR instructions are \
2443 supported for fast save and restore of the floating point context. \
2444 Presence of this bit also indicates that CR4.OSFXSR is available for an \
2445 operating system to indicate that it supports the FXSAVE and FXRSTOR \
2446 instructions.",
2447 has_fxsave_fxstor,
2448 edx_ecx,
2449 FeatureInfoFlags::FXSR
2450 );
2451
2452 check_flag!(
2453 doc = "SSE. The processor supports the SSE extensions.",
2454 has_sse,
2455 edx_ecx,
2456 FeatureInfoFlags::SSE
2457 );
2458
2459 check_flag!(
2460 doc = "SSE2. The processor supports the SSE2 extensions.",
2461 has_sse2,
2462 edx_ecx,
2463 FeatureInfoFlags::SSE2
2464 );
2465
2466 check_flag!(
2467 doc = "Self Snoop. The processor supports the management of conflicting memory \
2468 types by performing a snoop of its own cache structure for transactions \
2469 issued to the bus.",
2470 has_ss,
2471 edx_ecx,
2472 FeatureInfoFlags::SS
2473 );
2474
2475 check_flag!(
2476 doc = "Max APIC IDs reserved field is Valid. A value of 0 for HTT indicates \
2477 there is only a single logical processor in the package and software \
2478 should assume only a single APIC ID is reserved. A value of 1 for HTT \
2479 indicates the value in CPUID.1.EBX\\[23:16\\] (the Maximum number of \
2480 addressable IDs for logical processors in this package) is valid for the \
2481 package.",
2482 has_htt,
2483 edx_ecx,
2484 FeatureInfoFlags::HTT
2485 );
2486
2487 check_flag!(
2488 doc = "Thermal Monitor. The processor implements the thermal monitor automatic \
2489 thermal control circuitry (TCC).",
2490 has_tm,
2491 edx_ecx,
2492 FeatureInfoFlags::TM
2493 );
2494
2495 check_flag!(
2496 doc = "Pending Break Enable. The processor supports the use of the FERR#/PBE# \
2497 pin when the processor is in the stop-clock state (STPCLK# is asserted) \
2498 to signal the processor that an interrupt is pending and that the \
2499 processor should return to normal operation to handle the interrupt. Bit \
2500 10 (PBE enable) in the IA32_MISC_ENABLE MSR enables this capability.",
2501 has_pbe,
2502 edx_ecx,
2503 FeatureInfoFlags::PBE
2504 );
2505}
2506
2507impl Debug for FeatureInfo {
2508 fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
2509 f.debug_struct("FeatureInfo")
2510 .field("extended_family_id", &self.extended_family_id())
2511 .field("extended_model_id", &self.extended_model_id())
2512 .field("family_id", &self.family_id())
2513 .field("model_id", &self.model_id())
2514 .field("stepping_id", &self.stepping_id())
2515 .field("brand_index", &self.brand_index())
2516 .field("cflush_cache_line_size", &self.cflush_cache_line_size())
2517 .field("initial_local_apic_id", &self.initial_local_apic_id())
2518 .field(
2519 "max_logical_processor_ids",
2520 &self.max_logical_processor_ids(),
2521 )
2522 .field("edx_ecx", &self.edx_ecx)
2523 .finish()
2524 }
2525}
2526
2527bitflags! {
2528 #[repr(transparent)]
2529 #[derive(Debug, Clone, Copy, PartialEq, Eq)]
2530 struct FeatureInfoFlags: u64 {
2531 const SSE3 = 1 << 0;
2535 const PCLMULQDQ = 1 << 1;
2537 const DTES64 = 1 << 2;
2539 const MONITOR = 1 << 3;
2541 const DSCPL = 1 << 4;
2543 const VMX = 1 << 5;
2545 const SMX = 1 << 6;
2547 const EIST = 1 << 7;
2549 const TM2 = 1 << 8;
2551 const SSSE3 = 1 << 9;
2553 const CNXTID = 1 << 10;
2555 const FMA = 1 << 12;
2557 const CMPXCHG16B = 1 << 13;
2559 const PDCM = 1 << 15;
2561 const PCID = 1 << 17;
2563 const DCA = 1 << 18;
2565 const SSE41 = 1 << 19;
2567 const SSE42 = 1 << 20;
2569 const X2APIC = 1 << 21;
2571 const MOVBE = 1 << 22;
2573 const POPCNT = 1 << 23;
2575 const TSC_DEADLINE = 1 << 24;
2577 const AESNI = 1 << 25;
2579 const XSAVE = 1 << 26;
2581 const OSXSAVE = 1 << 27;
2583 const AVX = 1 << 28;
2585 const F16C = 1 << 29;
2587 const RDRAND = 1 << 30;
2589 const HYPERVISOR = 1 << 31;
2591
2592
2593 const FPU = 1 << 32;
2597 const VME = 1 << (32 + 1);
2599 const DE = 1 << (32 + 2);
2601 const PSE = 1 << (32 + 3);
2603 const TSC = 1 << (32 + 4);
2605 const MSR = 1 << (32 + 5);
2607 const PAE = 1 << (32 + 6);
2609 const MCE = 1 << (32 + 7);
2611 const CX8 = 1 << (32 + 8);
2613 const APIC = 1 << (32 + 9);
2615 const SEP = 1 << (32 + 11);
2617 const MTRR = 1 << (32 + 12);
2619 const PGE = 1 << (32 + 13);
2621 const MCA = 1 << (32 + 14);
2623 const CMOV = 1 << (32 + 15);
2625 const PAT = 1 << (32 + 16);
2627 const PSE36 = 1 << (32 + 17);
2629 const PSN = 1 << (32 + 18);
2631 const CLFSH = 1 << (32 + 19);
2633 const DS = 1 << (32 + 21);
2635 const ACPI = 1 << (32 + 22);
2637 const MMX = 1 << (32 + 23);
2639 const FXSR = 1 << (32 + 24);
2641 const SSE = 1 << (32 + 25);
2643 const SSE2 = 1 << (32 + 26);
2645 const SS = 1 << (32 + 27);
2647 const HTT = 1 << (32 + 28);
2649 const TM = 1 << (32 + 29);
2651 const PBE = 1 << (32 + 31);
2653 }
2654}
2655
2656#[derive(Clone, Copy)]
2663pub struct CacheParametersIter<R: CpuIdReader> {
2664 read: R,
2665 leaf: u32,
2666 current: u32,
2667}
2668
2669impl<R: CpuIdReader> Iterator for CacheParametersIter<R> {
2670 type Item = CacheParameter;
2671
2672 fn next(&mut self) -> Option<CacheParameter> {
2678 let res = self.read.cpuid2(self.leaf, self.current);
2679 let cp = CacheParameter {
2680 eax: res.eax,
2681 ebx: res.ebx,
2682 ecx: res.ecx,
2683 edx: res.edx,
2684 };
2685
2686 match cp.cache_type() {
2687 CacheType::Null => None,
2688 CacheType::Reserved => None,
2689 _ => {
2690 self.current += 1;
2691 Some(cp)
2692 }
2693 }
2694 }
2695}
2696
2697impl<R: CpuIdReader> Debug for CacheParametersIter<R> {
2698 fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
2699 let mut debug = f.debug_list();
2700 self.clone().for_each(|ref item| {
2701 debug.entry(item);
2702 });
2703 debug.finish()
2704 }
2705}
2706
2707#[derive(Copy, Clone, Eq, PartialEq)]
2712pub struct CacheParameter {
2713 eax: u32,
2714 ebx: u32,
2715 ecx: u32,
2716 edx: u32,
2717}
2718
2719#[derive(PartialEq, Eq, Debug)]
2721pub enum CacheType {
2722 Null = 0,
2724 Data,
2726 Instruction,
2728 Unified,
2730 Reserved,
2732}
2733
2734impl fmt::Display for CacheType {
2735 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2736 let typ = match self {
2737 CacheType::Null => "Null",
2738 CacheType::Data => "Data",
2739 CacheType::Instruction => "Instruction",
2740 CacheType::Unified => "Unified",
2741 CacheType::Reserved => "Reserved",
2742 };
2743
2744 f.write_str(typ)
2745 }
2746}
2747
2748impl CacheParameter {
2749 pub fn cache_type(&self) -> CacheType {
2754 let typ = get_bits(self.eax, 0, 4) as u8;
2755 match typ {
2756 0 => CacheType::Null,
2757 1 => CacheType::Data,
2758 2 => CacheType::Instruction,
2759 3 => CacheType::Unified,
2760 _ => CacheType::Reserved,
2761 }
2762 }
2763
2764 pub fn level(&self) -> u8 {
2769 get_bits(self.eax, 5, 7) as u8
2770 }
2771
2772 pub fn is_self_initializing(&self) -> bool {
2777 get_bits(self.eax, 8, 8) == 1
2778 }
2779
2780 pub fn is_fully_associative(&self) -> bool {
2785 get_bits(self.eax, 9, 9) == 1
2786 }
2787
2788 pub fn max_cores_for_cache(&self) -> usize {
2793 (get_bits(self.eax, 14, 25) + 1) as usize
2794 }
2795
2796 pub fn max_cores_for_package(&self) -> usize {
2801 (get_bits(self.eax, 26, 31) + 1) as usize
2802 }
2803
2804 pub fn coherency_line_size(&self) -> usize {
2809 (get_bits(self.ebx, 0, 11) + 1) as usize
2810 }
2811
2812 pub fn physical_line_partitions(&self) -> usize {
2817 (get_bits(self.ebx, 12, 21) + 1) as usize
2818 }
2819
2820 pub fn associativity(&self) -> usize {
2825 (get_bits(self.ebx, 22, 31) + 1) as usize
2826 }
2827
2828 pub fn sets(&self) -> usize {
2833 (self.ecx + 1) as usize
2834 }
2835
2836 pub fn is_write_back_invalidate(&self) -> bool {
2843 get_bits(self.edx, 0, 0) == 1
2844 }
2845
2846 pub fn is_inclusive(&self) -> bool {
2853 get_bits(self.edx, 1, 1) == 1
2854 }
2855
2856 pub fn has_complex_indexing(&self) -> bool {
2863 get_bits(self.edx, 2, 2) == 1
2864 }
2865}
2866
2867impl Debug for CacheParameter {
2868 fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
2869 f.debug_struct("CacheParameter")
2870 .field("cache_type", &self.cache_type())
2871 .field("level", &self.level())
2872 .field("is_self_initializing", &self.is_self_initializing())
2873 .field("is_fully_associative", &self.is_fully_associative())
2874 .field("max_cores_for_cache", &self.max_cores_for_cache())
2875 .field("max_cores_for_package", &self.max_cores_for_package())
2876 .field("coherency_line_size", &self.coherency_line_size())
2877 .field("physical_line_partitions", &self.physical_line_partitions())
2878 .field("associativity", &self.associativity())
2879 .field("sets", &self.sets())
2880 .field("is_write_back_invalidate", &self.is_write_back_invalidate())
2881 .field("is_inclusive", &self.is_inclusive())
2882 .field("has_complex_indexing", &self.has_complex_indexing())
2883 .finish()
2884 }
2885}
2886
2887#[derive(Eq, PartialEq)]
2892pub struct MonitorMwaitInfo {
2893 eax: u32,
2894 ebx: u32,
2895 ecx: u32,
2896 edx: u32,
2897}
2898
2899impl MonitorMwaitInfo {
2900 pub fn smallest_monitor_line(&self) -> u16 {
2905 get_bits(self.eax, 0, 15) as u16
2906 }
2907
2908 pub fn largest_monitor_line(&self) -> u16 {
2913 get_bits(self.ebx, 0, 15) as u16
2914 }
2915
2916 pub fn extensions_supported(&self) -> bool {
2921 get_bits(self.ecx, 0, 0) == 1
2922 }
2923
2924 pub fn interrupts_as_break_event(&self) -> bool {
2929 get_bits(self.ecx, 1, 1) == 1
2930 }
2931
2932 pub fn supported_c0_states(&self) -> u16 {
2937 get_bits(self.edx, 0, 3) as u16
2938 }
2939
2940 pub fn supported_c1_states(&self) -> u16 {
2945 get_bits(self.edx, 4, 7) as u16
2946 }
2947
2948 pub fn supported_c2_states(&self) -> u16 {
2953 get_bits(self.edx, 8, 11) as u16
2954 }
2955
2956 pub fn supported_c3_states(&self) -> u16 {
2961 get_bits(self.edx, 12, 15) as u16
2962 }
2963
2964 pub fn supported_c4_states(&self) -> u16 {
2969 get_bits(self.edx, 16, 19) as u16
2970 }
2971
2972 pub fn supported_c5_states(&self) -> u16 {
2977 get_bits(self.edx, 20, 23) as u16
2978 }
2979
2980 pub fn supported_c6_states(&self) -> u16 {
2985 get_bits(self.edx, 24, 27) as u16
2986 }
2987
2988 pub fn supported_c7_states(&self) -> u16 {
2993 get_bits(self.edx, 28, 31) as u16
2994 }
2995}
2996
2997impl Debug for MonitorMwaitInfo {
2998 fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
2999 f.debug_struct("MonitorMwaitInfo")
3000 .field("smallest_monitor_line", &self.smallest_monitor_line())
3001 .field("largest_monitor_line", &self.largest_monitor_line())
3002 .field("extensions_supported", &self.extensions_supported())
3003 .field(
3004 "interrupts_as_break_event",
3005 &self.interrupts_as_break_event(),
3006 )
3007 .field("supported_c0_states", &self.supported_c0_states())
3008 .field("supported_c1_states", &self.supported_c1_states())
3009 .field("supported_c2_states", &self.supported_c2_states())
3010 .field("supported_c3_states", &self.supported_c3_states())
3011 .field("supported_c4_states", &self.supported_c4_states())
3012 .field("supported_c5_states", &self.supported_c5_states())
3013 .field("supported_c6_states", &self.supported_c6_states())
3014 .field("supported_c7_states", &self.supported_c7_states())
3015 .finish()
3016 }
3017}
3018
3019pub struct ThermalPowerInfo {
3024 eax: ThermalPowerFeaturesEax,
3025 ebx: u32,
3026 ecx: ThermalPowerFeaturesEcx,
3027 _edx: u32,
3028}
3029
3030impl ThermalPowerInfo {
3031 pub fn dts_irq_threshold(&self) -> u8 {
3036 get_bits(self.ebx, 0, 3) as u8
3037 }
3038
3039 pub fn has_dts(&self) -> bool {
3044 self.eax.contains(ThermalPowerFeaturesEax::DTS)
3045 }
3046
3047 pub fn has_turbo_boost(&self) -> bool {
3053 self.eax.contains(ThermalPowerFeaturesEax::TURBO_BOOST)
3054 }
3055
3056 pub fn has_arat(&self) -> bool {
3061 self.eax.contains(ThermalPowerFeaturesEax::ARAT)
3062 }
3063
3064 pub fn has_pln(&self) -> bool {
3069 self.eax.contains(ThermalPowerFeaturesEax::PLN)
3070 }
3071
3072 pub fn has_ecmd(&self) -> bool {
3077 self.eax.contains(ThermalPowerFeaturesEax::ECMD)
3078 }
3079
3080 pub fn has_ptm(&self) -> bool {
3085 self.eax.contains(ThermalPowerFeaturesEax::PTM)
3086 }
3087
3088 pub fn has_hwp(&self) -> bool {
3094 self.eax.contains(ThermalPowerFeaturesEax::HWP)
3095 }
3096
3097 pub fn has_hwp_notification(&self) -> bool {
3102 self.eax.contains(ThermalPowerFeaturesEax::HWP_NOTIFICATION)
3103 }
3104
3105 pub fn has_hwp_activity_window(&self) -> bool {
3110 self.eax
3111 .contains(ThermalPowerFeaturesEax::HWP_ACTIVITY_WINDOW)
3112 }
3113
3114 pub fn has_hwp_energy_performance_preference(&self) -> bool {
3120 self.eax
3121 .contains(ThermalPowerFeaturesEax::HWP_ENERGY_PERFORMANCE_PREFERENCE)
3122 }
3123
3124 pub fn has_hwp_package_level_request(&self) -> bool {
3129 self.eax
3130 .contains(ThermalPowerFeaturesEax::HWP_PACKAGE_LEVEL_REQUEST)
3131 }
3132
3133 pub fn has_hdc(&self) -> bool {
3139 self.eax.contains(ThermalPowerFeaturesEax::HDC)
3140 }
3141
3142 pub fn has_turbo_boost3(&self) -> bool {
3147 self.eax.contains(ThermalPowerFeaturesEax::TURBO_BOOST_3)
3148 }
3149
3150 pub fn has_hwp_capabilities(&self) -> bool {
3155 self.eax.contains(ThermalPowerFeaturesEax::HWP_CAPABILITIES)
3156 }
3157
3158 pub fn has_hwp_peci_override(&self) -> bool {
3163 self.eax
3164 .contains(ThermalPowerFeaturesEax::HWP_PECI_OVERRIDE)
3165 }
3166
3167 pub fn has_flexible_hwp(&self) -> bool {
3172 self.eax.contains(ThermalPowerFeaturesEax::FLEXIBLE_HWP)
3173 }
3174
3175 pub fn has_hwp_fast_access_mode(&self) -> bool {
3180 self.eax
3181 .contains(ThermalPowerFeaturesEax::HWP_REQUEST_MSR_FAST_ACCESS)
3182 }
3183
3184 pub fn has_ignore_idle_processor_hwp_request(&self) -> bool {
3189 self.eax
3190 .contains(ThermalPowerFeaturesEax::IGNORE_IDLE_PROCESSOR_HWP_REQUEST)
3191 }
3192
3193 pub fn has_hw_coord_feedback(&self) -> bool {
3205 self.ecx
3206 .contains(ThermalPowerFeaturesEcx::HW_COORD_FEEDBACK)
3207 }
3208
3209 pub fn has_energy_bias_pref(&self) -> bool {
3216 self.ecx.contains(ThermalPowerFeaturesEcx::ENERGY_BIAS_PREF)
3217 }
3218}
3219
3220impl Debug for ThermalPowerInfo {
3221 fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
3222 f.debug_struct("ThermalPowerInfo")
3223 .field("dts_irq_threshold", &self.dts_irq_threshold())
3224 .field("has_dts", &self.has_dts())
3225 .field("has_arat", &self.has_arat())
3226 .field("has_pln", &self.has_pln())
3227 .field("has_ecmd", &self.has_ecmd())
3228 .field("has_ptm", &self.has_ptm())
3229 .field("has_hwp", &self.has_hwp())
3230 .field("has_hwp_notification", &self.has_hwp_notification())
3231 .field("has_hwp_activity_window", &self.has_hwp_activity_window())
3232 .field(
3233 "has_hwp_energy_performance_preference",
3234 &self.has_hwp_energy_performance_preference(),
3235 )
3236 .field(
3237 "has_hwp_package_level_request",
3238 &self.has_hwp_package_level_request(),
3239 )
3240 .field("has_hdc", &self.has_hdc())
3241 .field("has_turbo_boost3", &self.has_turbo_boost3())
3242 .field("has_hwp_capabilities", &self.has_hwp_capabilities())
3243 .field("has_hwp_peci_override", &self.has_hwp_peci_override())
3244 .field("has_flexible_hwp", &self.has_flexible_hwp())
3245 .field("has_hwp_fast_access_mode", &self.has_hwp_fast_access_mode())
3246 .field(
3247 "has_ignore_idle_processor_hwp_request",
3248 &self.has_ignore_idle_processor_hwp_request(),
3249 )
3250 .field("has_hw_coord_feedback", &self.has_hw_coord_feedback())
3251 .field("has_energy_bias_pref", &self.has_energy_bias_pref())
3252 .finish()
3253 }
3254}
3255
3256bitflags! {
3257 struct ThermalPowerFeaturesEax: u32 {
3258 const DTS = 1 << 0;
3260 const TURBO_BOOST = 1 << 1;
3262 const ARAT = 1 << 2;
3264 const RESERVED_3 = 1 << 3;
3266 const PLN = 1 << 4;
3268 const ECMD = 1 << 5;
3270 const PTM = 1 << 6;
3272 const HWP = 1 << 7;
3274 const HWP_NOTIFICATION = 1 << 8;
3276 const HWP_ACTIVITY_WINDOW = 1 << 9;
3278 const HWP_ENERGY_PERFORMANCE_PREFERENCE = 1 << 10;
3280 const HWP_PACKAGE_LEVEL_REQUEST = 1 << 11;
3282 const RESERVED_12 = 1 << 12;
3284 const HDC = 1 << 13;
3286 const TURBO_BOOST_3 = 1 << 14;
3288 const HWP_CAPABILITIES = 1 << 15;
3290 const HWP_PECI_OVERRIDE = 1 << 16;
3292 const FLEXIBLE_HWP = 1 << 17;
3294 const HWP_REQUEST_MSR_FAST_ACCESS = 1 << 18;
3296 const RESERVED_19 = 1 << 19;
3298 const IGNORE_IDLE_PROCESSOR_HWP_REQUEST = 1 << 20;
3300 }
3302}
3303
3304bitflags! {
3305 struct ThermalPowerFeaturesEcx: u32 {
3306 const HW_COORD_FEEDBACK = 1 << 0;
3307
3308 const ENERGY_BIAS_PREF = 1 << 3;
3310 }
3311}
3312
3313pub struct ExtendedFeatures {
3318 _eax: u32,
3319 ebx: ExtendedFeaturesEbx,
3320 ecx: ExtendedFeaturesEcx,
3321 edx: ExtendedFeaturesEdx,
3322 eax1: ExtendedFeaturesEax1,
3323 _ebx1: u32,
3324 _ecx1: u32,
3325 edx1: ExtendedFeaturesEdx1,
3326}
3327
3328impl ExtendedFeatures {
3329 #[inline]
3334 pub const fn has_fsgsbase(&self) -> bool {
3335 self.ebx.contains(ExtendedFeaturesEbx::FSGSBASE)
3336 }
3337
3338 #[inline]
3343 pub const fn has_tsc_adjust_msr(&self) -> bool {
3344 self.ebx.contains(ExtendedFeaturesEbx::ADJUST_MSR)
3345 }
3346
3347 #[inline]
3352 pub const fn has_bmi1(&self) -> bool {
3353 self.ebx.contains(ExtendedFeaturesEbx::BMI1)
3354 }
3355
3356 #[inline]
3361 pub const fn has_hle(&self) -> bool {
3362 self.ebx.contains(ExtendedFeaturesEbx::HLE)
3363 }
3364
3365 #[inline]
3370 pub const fn has_avx2(&self) -> bool {
3371 self.ebx.contains(ExtendedFeaturesEbx::AVX2)
3372 }
3373
3374 #[inline]
3380 pub const fn has_fdp(&self) -> bool {
3381 self.ebx.contains(ExtendedFeaturesEbx::FDP)
3382 }
3383
3384 #[inline]
3389 pub const fn has_smep(&self) -> bool {
3390 self.ebx.contains(ExtendedFeaturesEbx::SMEP)
3391 }
3392
3393 #[inline]
3398 pub const fn has_bmi2(&self) -> bool {
3399 self.ebx.contains(ExtendedFeaturesEbx::BMI2)
3400 }
3401
3402 #[inline]
3407 pub const fn has_rep_movsb_stosb(&self) -> bool {
3408 self.ebx.contains(ExtendedFeaturesEbx::REP_MOVSB_STOSB)
3409 }
3410
3411 #[inline]
3417 pub const fn has_invpcid(&self) -> bool {
3418 self.ebx.contains(ExtendedFeaturesEbx::INVPCID)
3419 }
3420
3421 #[inline]
3426 pub const fn has_rtm(&self) -> bool {
3427 self.ebx.contains(ExtendedFeaturesEbx::RTM)
3428 }
3429
3430 #[inline]
3435 pub const fn has_rdtm(&self) -> bool {
3436 self.ebx.contains(ExtendedFeaturesEbx::RDTM)
3437 }
3438
3439 #[inline]
3444 pub const fn has_fpu_cs_ds_deprecated(&self) -> bool {
3445 self.ebx.contains(ExtendedFeaturesEbx::DEPRECATE_FPU_CS_DS)
3446 }
3447
3448 #[inline]
3453 pub const fn has_mpx(&self) -> bool {
3454 self.ebx.contains(ExtendedFeaturesEbx::MPX)
3455 }
3456
3457 #[inline]
3462 pub const fn has_rdta(&self) -> bool {
3463 self.ebx.contains(ExtendedFeaturesEbx::RDTA)
3464 }
3465
3466 #[inline]
3471 pub const fn has_rdseed(&self) -> bool {
3472 self.ebx.contains(ExtendedFeaturesEbx::RDSEED)
3473 }
3474
3475 #[inline]
3480 pub const fn has_adx(&self) -> bool {
3481 self.ebx.contains(ExtendedFeaturesEbx::ADX)
3482 }
3483
3484 #[inline]
3490 pub const fn has_smap(&self) -> bool {
3491 self.ebx.contains(ExtendedFeaturesEbx::SMAP)
3492 }
3493
3494 #[inline]
3499 pub const fn has_clflushopt(&self) -> bool {
3500 self.ebx.contains(ExtendedFeaturesEbx::CLFLUSHOPT)
3501 }
3502
3503 #[inline]
3508 pub const fn has_processor_trace(&self) -> bool {
3509 self.ebx.contains(ExtendedFeaturesEbx::PROCESSOR_TRACE)
3510 }
3511
3512 #[inline]
3517 pub const fn has_sha(&self) -> bool {
3518 self.ebx.contains(ExtendedFeaturesEbx::SHA)
3519 }
3520
3521 #[inline]
3526 pub const fn has_sgx(&self) -> bool {
3527 self.ebx.contains(ExtendedFeaturesEbx::SGX)
3528 }
3529
3530 #[inline]
3535 pub const fn has_avx512f(&self) -> bool {
3536 self.ebx.contains(ExtendedFeaturesEbx::AVX512F)
3537 }
3538
3539 #[inline]
3544 pub const fn has_avx512dq(&self) -> bool {
3545 self.ebx.contains(ExtendedFeaturesEbx::AVX512DQ)
3546 }
3547
3548 #[inline]
3553 pub const fn has_avx512_ifma(&self) -> bool {
3554 self.ebx.contains(ExtendedFeaturesEbx::AVX512_IFMA)
3555 }
3556
3557 #[inline]
3562 pub const fn has_avx512pf(&self) -> bool {
3563 self.ebx.contains(ExtendedFeaturesEbx::AVX512PF)
3564 }
3565
3566 #[inline]
3571 pub const fn has_avx512er(&self) -> bool {
3572 self.ebx.contains(ExtendedFeaturesEbx::AVX512ER)
3573 }
3574
3575 #[inline]
3580 pub const fn has_avx512cd(&self) -> bool {
3581 self.ebx.contains(ExtendedFeaturesEbx::AVX512CD)
3582 }
3583
3584 #[inline]
3589 pub const fn has_avx512bw(&self) -> bool {
3590 self.ebx.contains(ExtendedFeaturesEbx::AVX512BW)
3591 }
3592
3593 #[inline]
3598 pub const fn has_avx512vl(&self) -> bool {
3599 self.ebx.contains(ExtendedFeaturesEbx::AVX512VL)
3600 }
3601
3602 #[inline]
3607 pub const fn has_clwb(&self) -> bool {
3608 self.ebx.contains(ExtendedFeaturesEbx::CLWB)
3609 }
3610
3611 #[inline]
3616 pub const fn has_prefetchwt1(&self) -> bool {
3617 self.ecx.contains(ExtendedFeaturesEcx::PREFETCHWT1)
3618 }
3619
3620 #[inline]
3624 pub const fn has_avx512vbmi(&self) -> bool {
3625 self.ecx.contains(ExtendedFeaturesEcx::AVX512VBMI)
3626 }
3627
3628 #[inline]
3633 pub const fn has_umip(&self) -> bool {
3634 self.ecx.contains(ExtendedFeaturesEcx::UMIP)
3635 }
3636
3637 #[inline]
3642 pub const fn has_pku(&self) -> bool {
3643 self.ecx.contains(ExtendedFeaturesEcx::PKU)
3644 }
3645
3646 #[inline]
3652 pub const fn has_ospke(&self) -> bool {
3653 self.ecx.contains(ExtendedFeaturesEcx::OSPKE)
3654 }
3655
3656 #[inline]
3660 pub const fn has_waitpkg(&self) -> bool {
3661 self.ecx.contains(ExtendedFeaturesEcx::WAITPKG)
3662 }
3663
3664 #[deprecated(since = "11.4.0", note = "Please use `has_avx512vbmi2` instead")]
3668 #[inline]
3669 pub const fn has_av512vbmi2(&self) -> bool {
3670 self.ecx.contains(ExtendedFeaturesEcx::AVX512VBMI2)
3671 }
3672
3673 #[inline]
3677 pub const fn has_avx512vbmi2(&self) -> bool {
3678 self.ecx.contains(ExtendedFeaturesEcx::AVX512VBMI2)
3679 }
3680
3681 #[inline]
3687 pub const fn has_cet_ss(&self) -> bool {
3688 self.ecx.contains(ExtendedFeaturesEcx::CETSS)
3689 }
3690
3691 #[inline]
3695 pub const fn has_gfni(&self) -> bool {
3696 self.ecx.contains(ExtendedFeaturesEcx::GFNI)
3697 }
3698
3699 #[inline]
3703 pub const fn has_vaes(&self) -> bool {
3704 self.ecx.contains(ExtendedFeaturesEcx::VAES)
3705 }
3706
3707 #[inline]
3711 pub const fn has_vpclmulqdq(&self) -> bool {
3712 self.ecx.contains(ExtendedFeaturesEcx::VPCLMULQDQ)
3713 }
3714
3715 #[inline]
3720 pub const fn has_avx512vnni(&self) -> bool {
3721 self.ecx.contains(ExtendedFeaturesEcx::AVX512VNNI)
3722 }
3723
3724 #[inline]
3728 pub const fn has_avx512bitalg(&self) -> bool {
3729 self.ecx.contains(ExtendedFeaturesEcx::AVX512BITALG)
3730 }
3731
3732 #[inline]
3737 pub const fn has_tme_en(&self) -> bool {
3738 self.ecx.contains(ExtendedFeaturesEcx::TMEEN)
3739 }
3740
3741 #[inline]
3745 pub const fn has_avx512vpopcntdq(&self) -> bool {
3746 self.ecx.contains(ExtendedFeaturesEcx::AVX512VPOPCNTDQ)
3747 }
3748
3749 #[inline]
3754 pub const fn has_la57(&self) -> bool {
3755 self.ecx.contains(ExtendedFeaturesEcx::LA57)
3756 }
3757
3758 #[inline]
3768 pub const fn has_rdpid(&self) -> bool {
3769 self.ecx.contains(ExtendedFeaturesEcx::RDPID)
3770 }
3771
3772 #[inline]
3777 pub const fn has_sgx_lc(&self) -> bool {
3778 self.ecx.contains(ExtendedFeaturesEcx::SGX_LC)
3779 }
3780
3781 #[inline]
3786 pub fn mawau_value(&self) -> u8 {
3787 get_bits(self.ecx.bits(), 17, 21) as u8
3788 }
3789
3790 #[inline]
3795 pub const fn has_avx512_4vnniw(&self) -> bool {
3796 self.edx.contains(ExtendedFeaturesEdx::AVX512_4VNNIW)
3797 }
3798
3799 #[inline]
3804 pub const fn has_avx512_4fmaps(&self) -> bool {
3805 self.edx.contains(ExtendedFeaturesEdx::AVX512_4FMAPS)
3806 }
3807
3808 #[inline]
3813 pub const fn has_avx512_vp2intersect(&self) -> bool {
3814 self.edx.contains(ExtendedFeaturesEdx::AVX512_VP2INTERSECT)
3815 }
3816
3817 #[inline]
3822 pub const fn has_amx_bf16(&self) -> bool {
3823 self.edx.contains(ExtendedFeaturesEdx::AMX_BF16)
3824 }
3825
3826 #[inline]
3831 pub const fn has_avx512_fp16(&self) -> bool {
3832 self.edx.contains(ExtendedFeaturesEdx::AVX512_FP16)
3833 }
3834
3835 #[inline]
3840 pub const fn has_amx_tile(&self) -> bool {
3841 self.edx.contains(ExtendedFeaturesEdx::AMX_TILE)
3842 }
3843
3844 #[inline]
3849 pub const fn has_amx_int8(&self) -> bool {
3850 self.edx.contains(ExtendedFeaturesEdx::AMX_INT8)
3851 }
3852
3853 #[inline]
3858 pub const fn has_avx_vnni(&self) -> bool {
3859 self.eax1.contains(ExtendedFeaturesEax1::AVX_VNNI)
3860 }
3861
3862 #[inline]
3867 pub const fn has_avx512_bf16(&self) -> bool {
3868 self.eax1.contains(ExtendedFeaturesEax1::AVX512_BF16)
3869 }
3870
3871 #[inline]
3876 pub const fn has_fzrm(&self) -> bool {
3877 self.eax1.contains(ExtendedFeaturesEax1::FZRM)
3878 }
3879
3880 #[inline]
3885 pub const fn has_fsrs(&self) -> bool {
3886 self.eax1.contains(ExtendedFeaturesEax1::FSRS)
3887 }
3888
3889 #[inline]
3894 pub const fn has_fsrcrs(&self) -> bool {
3895 self.eax1.contains(ExtendedFeaturesEax1::FSRCRS)
3896 }
3897
3898 #[inline]
3903 pub const fn has_hreset(&self) -> bool {
3904 self.eax1.contains(ExtendedFeaturesEax1::HRESET)
3905 }
3906
3907 #[inline]
3912 pub const fn has_avx_ifma(&self) -> bool {
3913 self.eax1.contains(ExtendedFeaturesEax1::AVX_IFMA)
3914 }
3915
3916 #[inline]
3921 pub const fn has_lam(&self) -> bool {
3922 self.eax1.contains(ExtendedFeaturesEax1::LAM)
3923 }
3924
3925 #[inline]
3930 pub const fn has_msrlist(&self) -> bool {
3931 self.eax1.contains(ExtendedFeaturesEax1::MSRLIST)
3932 }
3933
3934 #[inline]
3939 pub const fn has_invd_disable_post_bios_done(&self) -> bool {
3940 self.eax1
3941 .contains(ExtendedFeaturesEax1::INVD_DISABLE_POST_BIOS_DONE)
3942 }
3943
3944 #[inline]
3949 pub const fn has_avx_vnni_int8(&self) -> bool {
3950 self.edx1.contains(ExtendedFeaturesEdx1::AVX_VNNI_INT8)
3951 }
3952
3953 #[inline]
3958 pub const fn has_avx_ne_convert(&self) -> bool {
3959 self.edx1.contains(ExtendedFeaturesEdx1::AVX_NE_CONVERT)
3960 }
3961
3962 #[inline]
3967 pub const fn has_avx_vnni_int16(&self) -> bool {
3968 self.edx1.contains(ExtendedFeaturesEdx1::AVX_VNNI_INT16)
3969 }
3970
3971 #[inline]
3976 pub const fn has_prefetchi(&self) -> bool {
3977 self.edx1.contains(ExtendedFeaturesEdx1::PREFETCHI)
3978 }
3979
3980 #[inline]
3985 pub const fn has_uiret_uif(&self) -> bool {
3986 self.edx1.contains(ExtendedFeaturesEdx1::UIRET_UIF)
3987 }
3988
3989 #[inline]
3994 pub const fn has_cet_sss(&self) -> bool {
3995 self.edx1.contains(ExtendedFeaturesEdx1::CET_SSS)
3996 }
3997
3998 #[inline]
4003 pub const fn has_avx10(&self) -> bool {
4004 self.edx1.contains(ExtendedFeaturesEdx1::AVX10)
4005 }
4006}
4007
4008impl Debug for ExtendedFeatures {
4009 fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
4010 f.debug_struct("ExtendedFeatures")
4011 .field("ebx", &self.ebx)
4012 .field("ecx", &self.ecx)
4013 .field("mawau_value", &self.mawau_value())
4014 .finish()
4015 }
4016}
4017
4018bitflags! {
4019 #[repr(transparent)]
4020 #[derive(Debug, Clone, Copy, PartialEq, Eq)]
4021 struct ExtendedFeaturesEbx: u32 {
4022 const FSGSBASE = 1 << 0;
4024 const ADJUST_MSR = 1 << 1;
4026 const SGX = 1 << 2;
4028 const BMI1 = 1 << 3;
4030 const HLE = 1 << 4;
4032 const AVX2 = 1 << 5;
4034 const FDP = 1 << 6;
4036 const SMEP = 1 << 7;
4038 const BMI2 = 1 << 8;
4040 const REP_MOVSB_STOSB = 1 << 9;
4042 const INVPCID = 1 << 10;
4044 const RTM = 1 << 11;
4046 const RDTM = 1 << 12;
4048 const DEPRECATE_FPU_CS_DS = 1 << 13;
4050 const MPX = 1 << 14;
4052 const RDTA = 1 << 15;
4054 const AVX512F = 1 << 16;
4056 const AVX512DQ = 1 << 17;
4058 const RDSEED = 1 << 18;
4060 const ADX = 1 << 19;
4062 const SMAP = 1 << 20;
4064 const AVX512_IFMA = 1 << 21;
4066 const CLFLUSHOPT = 1 << 23;
4069 const CLWB = 1 << 24;
4071 const PROCESSOR_TRACE = 1 << 25;
4073 const AVX512PF = 1 << 26;
4075 const AVX512ER = 1 << 27;
4077 const AVX512CD = 1 << 28;
4079 const SHA = 1 << 29;
4081 const AVX512BW = 1 << 30;
4083 const AVX512VL = 1 << 31;
4085 }
4086}
4087
4088bitflags! {
4089 #[repr(transparent)]
4090 #[derive(Debug, Clone, Copy, PartialEq, Eq)]
4091 struct ExtendedFeaturesEcx: u32 {
4092 const PREFETCHWT1 = 1 << 0;
4094 const AVX512VBMI = 1 << 1;
4096 const UMIP = 1 << 2;
4098 const PKU = 1 << 3;
4100 const OSPKE = 1 << 4;
4102 const WAITPKG = 1 << 5;
4104 const AVX512VBMI2 = 1 << 6;
4106 const CETSS = 1 << 7;
4110 const GFNI = 1 << 8;
4112 const VAES = 1 << 9;
4114 const VPCLMULQDQ = 1 << 10;
4116 const AVX512VNNI = 1 << 11;
4118 const AVX512BITALG = 1 << 12;
4120 const TMEEN = 1 << 13;
4123 const AVX512VPOPCNTDQ = 1 << 14;
4125
4126 const LA57 = 1 << 16;
4130
4131 const RDPID = 1 << 22;
4135
4136 const SGX_LC = 1 << 30;
4140 }
4141}
4142
4143bitflags! {
4144 #[repr(transparent)]
4145 #[derive(Debug, Clone, Copy, PartialEq, Eq)]
4146 struct ExtendedFeaturesEdx: u32 {
4147 const AVX512_4VNNIW = 1 << 2;
4149 const AVX512_4FMAPS = 1 << 3;
4151 const AVX512_VP2INTERSECT = 1 << 8;
4153 const AMX_BF16 = 1 << 22;
4155 const AVX512_FP16 = 1 << 23;
4157 const AMX_TILE = 1 << 24;
4159 const AMX_INT8 = 1 << 25;
4161 }
4162}
4163
4164bitflags! {
4165 #[repr(transparent)]
4166 #[derive(Debug, Clone, Copy, PartialEq, Eq)]
4167 struct ExtendedFeaturesEax1: u32 {
4168 const AVX_VNNI = 1 << 4;
4171 const AVX512_BF16 = 1 << 5;
4173 const FZRM = 1 << 10;
4175 const FSRS = 1 << 11;
4177 const FSRCRS = 1 << 12;
4179 const HRESET = 1 << 22;
4181 const AVX_IFMA = 1 << 23;
4183 const LAM = 1 << 26;
4185 const MSRLIST = 1 << 27;
4187 const INVD_DISABLE_POST_BIOS_DONE = 1 << 30;
4189 }
4190}
4191
4192bitflags! {
4193 #[repr(transparent)]
4194 #[derive(Debug, Clone, Copy, PartialEq, Eq)]
4195 struct ExtendedFeaturesEdx1: u32 {
4196 const AVX_VNNI_INT8 = 1 << 4;
4199 const AVX_NE_CONVERT = 1 << 5;
4201 const AVX_VNNI_INT16 = 1 << 10;
4203 const PREFETCHI = 1 << 14;
4205 const UIRET_UIF = 1 << 17;
4207 const CET_SSS = 1 << 18;
4209 const AVX10 = 1 << 19;
4212 }
4213}
4214
4215pub struct DirectCacheAccessInfo {
4220 eax: u32,
4221}
4222
4223impl DirectCacheAccessInfo {
4224 pub fn get_dca_cap_value(&self) -> u32 {
4226 self.eax
4227 }
4228}
4229
4230impl Debug for DirectCacheAccessInfo {
4231 fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
4232 f.debug_struct("DirectCacheAccessInfo")
4233 .field("dca_cap_value", &self.get_dca_cap_value())
4234 .finish()
4235 }
4236}
4237
4238pub struct PerformanceMonitoringInfo {
4243 eax: u32,
4244 ebx: PerformanceMonitoringFeaturesEbx,
4245 _ecx: u32,
4246 edx: u32,
4247}
4248
4249impl PerformanceMonitoringInfo {
4250 pub fn version_id(&self) -> u8 {
4252 get_bits(self.eax, 0, 7) as u8
4253 }
4254
4255 pub fn number_of_counters(&self) -> u8 {
4257 get_bits(self.eax, 8, 15) as u8
4258 }
4259
4260 pub fn counter_bit_width(&self) -> u8 {
4262 get_bits(self.eax, 16, 23) as u8
4263 }
4264
4265 pub fn ebx_length(&self) -> u8 {
4267 get_bits(self.eax, 24, 31) as u8
4268 }
4269
4270 pub fn fixed_function_counters(&self) -> u8 {
4272 get_bits(self.edx, 0, 4) as u8
4273 }
4274
4275 pub fn fixed_function_counters_bit_width(&self) -> u8 {
4277 get_bits(self.edx, 5, 12) as u8
4278 }
4279
4280 check_bit_fn!(
4281 doc = "AnyThread deprecation",
4282 has_any_thread_deprecation,
4283 edx,
4284 15
4285 );
4286
4287 check_flag!(
4288 doc = "Core cycle event not available if 1.",
4289 is_core_cyc_ev_unavailable,
4290 ebx,
4291 PerformanceMonitoringFeaturesEbx::CORE_CYC_EV_UNAVAILABLE
4292 );
4293
4294 check_flag!(
4295 doc = "Instruction retired event not available if 1.",
4296 is_inst_ret_ev_unavailable,
4297 ebx,
4298 PerformanceMonitoringFeaturesEbx::INST_RET_EV_UNAVAILABLE
4299 );
4300
4301 check_flag!(
4302 doc = "Reference cycles event not available if 1.",
4303 is_ref_cycle_ev_unavailable,
4304 ebx,
4305 PerformanceMonitoringFeaturesEbx::REF_CYC_EV_UNAVAILABLE
4306 );
4307
4308 check_flag!(
4309 doc = "Last-level cache reference event not available if 1.",
4310 is_cache_ref_ev_unavailable,
4311 ebx,
4312 PerformanceMonitoringFeaturesEbx::CACHE_REF_EV_UNAVAILABLE
4313 );
4314
4315 check_flag!(
4316 doc = "Last-level cache misses event not available if 1.",
4317 is_ll_cache_miss_ev_unavailable,
4318 ebx,
4319 PerformanceMonitoringFeaturesEbx::LL_CACHE_MISS_EV_UNAVAILABLE
4320 );
4321
4322 check_flag!(
4323 doc = "Branch instruction retired event not available if 1.",
4324 is_branch_inst_ret_ev_unavailable,
4325 ebx,
4326 PerformanceMonitoringFeaturesEbx::BRANCH_INST_RET_EV_UNAVAILABLE
4327 );
4328
4329 check_flag!(
4330 doc = "Branch mispredict retired event not available if 1.",
4331 is_branch_midpred_ev_unavailable,
4332 ebx,
4333 PerformanceMonitoringFeaturesEbx::BRANCH_MISPRED_EV_UNAVAILABLE
4334 );
4335}
4336
4337impl Debug for PerformanceMonitoringInfo {
4338 fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
4339 f.debug_struct("PerformanceMonitoringInfo")
4340 .field("version_id", &self.version_id())
4341 .field("number_of_counters", &self.number_of_counters())
4342 .field("counter_bit_width", &self.counter_bit_width())
4343 .field("ebx_length", &self.ebx_length())
4344 .field("fixed_function_counters", &self.fixed_function_counters())
4345 .field(
4346 "fixed_function_counters_bit_width",
4347 &self.fixed_function_counters_bit_width(),
4348 )
4349 .finish()
4350 }
4351}
4352
4353bitflags! {
4354 #[repr(transparent)]
4355 #[derive(Debug, Clone, Copy, PartialEq, Eq)]
4356 struct PerformanceMonitoringFeaturesEbx: u32 {
4357 const CORE_CYC_EV_UNAVAILABLE = 1 << 0;
4359 const INST_RET_EV_UNAVAILABLE = 1 << 1;
4361 const REF_CYC_EV_UNAVAILABLE = 1 << 2;
4363 const CACHE_REF_EV_UNAVAILABLE = 1 << 3;
4365 const LL_CACHE_MISS_EV_UNAVAILABLE = 1 << 4;
4367 const BRANCH_INST_RET_EV_UNAVAILABLE = 1 << 5;
4369 const BRANCH_MISPRED_EV_UNAVAILABLE = 1 << 6;
4371 }
4372}
4373
4374#[derive(Clone)]
4383pub struct ExtendedTopologyIter<R: CpuIdReader> {
4384 read: R,
4385 level: u32,
4386 is_v2: bool,
4387}
4388
4389#[derive(PartialEq, Eq)]
4393pub struct ExtendedTopologyLevel {
4394 eax: u32,
4395 ebx: u32,
4396 ecx: u32,
4397 edx: u32,
4398}
4399
4400impl fmt::Debug for ExtendedTopologyLevel {
4401 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
4402 f.debug_struct("ExtendedTopologyLevel")
4403 .field("processors", &self.processors())
4404 .field("number", &self.level_number())
4405 .field("type", &self.level_type())
4406 .field("x2apic_id", &self.x2apic_id())
4407 .field("next_apic_id", &self.shift_right_for_next_apic_id())
4408 .finish()
4409 }
4410}
4411
4412impl ExtendedTopologyLevel {
4413 pub fn processors(&self) -> u16 {
4416 get_bits(self.ebx, 0, 15) as u16
4417 }
4418
4419 pub fn level_number(&self) -> u8 {
4421 get_bits(self.ecx, 0, 7) as u8
4422 }
4423
4424 pub fn level_type(&self) -> TopologyType {
4426 match get_bits(self.ecx, 8, 15) {
4427 0 => TopologyType::Invalid,
4428 1 => TopologyType::SMT,
4429 2 => TopologyType::Core,
4430 3 => TopologyType::Module,
4431 4 => TopologyType::Tile,
4432 5 => TopologyType::Die,
4433 _ => unreachable!(),
4434 }
4435 }
4436
4437 pub fn x2apic_id(&self) -> u32 {
4439 self.edx
4440 }
4441
4442 pub fn shift_right_for_next_apic_id(&self) -> u32 {
4445 get_bits(self.eax, 0, 4)
4446 }
4447}
4448
4449#[derive(PartialEq, Eq, Debug)]
4451pub enum TopologyType {
4452 Invalid = 0,
4453 SMT = 1,
4455 Core = 2,
4456 Module = 3,
4457 Tile = 4,
4458 Die = 5,
4459}
4460
4461impl fmt::Display for TopologyType {
4462 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
4463 let data = match self {
4464 TopologyType::Invalid => "Invalid",
4465 TopologyType::SMT => "SMT",
4466 TopologyType::Core => "Core",
4467 TopologyType::Module => "Module",
4468 TopologyType::Tile => "Tile",
4469 TopologyType::Die => "Die",
4470 };
4471
4472 f.write_str(data)
4473 }
4474}
4475
4476impl<R: CpuIdReader> Iterator for ExtendedTopologyIter<R> {
4477 type Item = ExtendedTopologyLevel;
4478
4479 fn next(&mut self) -> Option<ExtendedTopologyLevel> {
4480 let res = if self.is_v2 {
4481 self.read.cpuid2(EAX_EXTENDED_TOPOLOGY_INFO_V2, self.level)
4482 } else {
4483 self.read.cpuid2(EAX_EXTENDED_TOPOLOGY_INFO, self.level)
4484 };
4485 self.level += 1;
4486
4487 let et = ExtendedTopologyLevel {
4488 eax: res.eax,
4489 ebx: res.ebx,
4490 ecx: res.ecx,
4491 edx: res.edx,
4492 };
4493
4494 match et.level_type() {
4495 TopologyType::Invalid => None,
4496 _ => Some(et),
4497 }
4498 }
4499}
4500
4501impl<R: CpuIdReader> Debug for ExtendedTopologyIter<R> {
4502 fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
4503 let mut debug = f.debug_list();
4504 self.clone().for_each(|ref item| {
4505 debug.entry(item);
4506 });
4507 debug.finish()
4508 }
4509}
4510
4511bitflags! {
4512 #[repr(transparent)]
4513 #[derive(Debug, Clone, Copy, PartialEq, Eq)]
4514 struct ExtendedStateInfoXCR0Flags: u32 {
4515 const LEGACY_X87 = 1 << 0;
4517
4518 const SSE128 = 1 << 1;
4520
4521 const AVX256 = 1 << 2;
4523
4524 const MPX_BNDREGS = 1 << 3;
4526
4527 const MPX_BNDCSR = 1 << 4;
4529
4530 const AVX512_OPMASK = 1 << 5;
4532
4533 const AVX512_ZMM_HI256 = 1 << 6;
4535
4536 const AVX512_ZMM_HI16 = 1 << 7;
4538
4539 const PKRU = 1 << 9;
4541
4542 const IA32_XSS_HDC = 1 << 13;
4544
4545 const AMX_TILECFG = 1 << 17;
4547
4548 const AMX_TILEDATA = 1 << 18;
4550 }
4551}
4552
4553bitflags! {
4554 #[repr(transparent)]
4555 #[derive(Debug, Clone, Copy, PartialEq, Eq)]
4556 struct ExtendedStateInfoXSSFlags: u32 {
4557 const PT = 1 << 8;
4559
4560 const PASID = 1 << 10;
4562
4563 const CET_USER = 1 << 11;
4565
4566 const CET_SUPERVISOR = 1 << 12;
4568
4569 const HDC = 1 << 13;
4571
4572 const UINTR = 1 << 14;
4574
4575 const LBR = 1 << 15;
4577
4578 const HWP = 1 << 16;
4580 }
4581}
4582
4583pub struct ExtendedStateInfo<R: CpuIdReader> {
4588 read: R,
4589 eax: ExtendedStateInfoXCR0Flags,
4590 ebx: u32,
4591 ecx: u32,
4592 _edx: u32,
4593 eax1: u32,
4594 ebx1: u32,
4595 ecx1: ExtendedStateInfoXSSFlags,
4596 _edx1: u32,
4597}
4598
4599impl<F: CpuIdReader> ExtendedStateInfo<F> {
4600 check_flag!(
4601 doc = "Support for legacy x87 in XCR0.",
4602 xcr0_supports_legacy_x87,
4603 eax,
4604 ExtendedStateInfoXCR0Flags::LEGACY_X87
4605 );
4606
4607 check_flag!(
4608 doc = "Support for SSE 128-bit in XCR0.",
4609 xcr0_supports_sse_128,
4610 eax,
4611 ExtendedStateInfoXCR0Flags::SSE128
4612 );
4613
4614 check_flag!(
4615 doc = "Support for AVX 256-bit in XCR0.",
4616 xcr0_supports_avx_256,
4617 eax,
4618 ExtendedStateInfoXCR0Flags::AVX256
4619 );
4620
4621 check_flag!(
4622 doc = "Support for MPX BNDREGS in XCR0.",
4623 xcr0_supports_mpx_bndregs,
4624 eax,
4625 ExtendedStateInfoXCR0Flags::MPX_BNDREGS
4626 );
4627
4628 check_flag!(
4629 doc = "Support for MPX BNDCSR in XCR0.",
4630 xcr0_supports_mpx_bndcsr,
4631 eax,
4632 ExtendedStateInfoXCR0Flags::MPX_BNDCSR
4633 );
4634
4635 check_flag!(
4636 doc = "Support for AVX512 OPMASK in XCR0.",
4637 xcr0_supports_avx512_opmask,
4638 eax,
4639 ExtendedStateInfoXCR0Flags::AVX512_OPMASK
4640 );
4641
4642 check_flag!(
4643 doc = "Support for AVX512 ZMM Hi256 XCR0.",
4644 xcr0_supports_avx512_zmm_hi256,
4645 eax,
4646 ExtendedStateInfoXCR0Flags::AVX512_ZMM_HI256
4647 );
4648
4649 check_flag!(
4650 doc = "Support for AVX512 ZMM Hi16 in XCR0.",
4651 xcr0_supports_avx512_zmm_hi16,
4652 eax,
4653 ExtendedStateInfoXCR0Flags::AVX512_ZMM_HI16
4654 );
4655
4656 check_flag!(
4657 doc = "Support for PKRU in XCR0.",
4658 xcr0_supports_pkru,
4659 eax,
4660 ExtendedStateInfoXCR0Flags::PKRU
4661 );
4662
4663 check_flag!(
4664 doc = "Support for PT in IA32_XSS.",
4665 ia32_xss_supports_pt,
4666 ecx1,
4667 ExtendedStateInfoXSSFlags::PT
4668 );
4669
4670 check_flag!(
4671 doc = "Support for HDC in IA32_XSS.",
4672 ia32_xss_supports_hdc,
4673 ecx1,
4674 ExtendedStateInfoXSSFlags::HDC
4675 );
4676
4677 pub fn xsave_area_size_enabled_features(&self) -> u32 {
4681 self.ebx
4682 }
4683
4684 pub fn xsave_area_size_supported_features(&self) -> u32 {
4688 self.ecx
4689 }
4690
4691 pub fn has_xsaveopt(&self) -> bool {
4693 self.eax1 & 0x1 > 0
4694 }
4695
4696 pub fn has_xsavec(&self) -> bool {
4698 self.eax1 & 0b10 > 0
4699 }
4700
4701 pub fn has_xgetbv(&self) -> bool {
4703 self.eax1 & 0b100 > 0
4704 }
4705
4706 pub fn has_xsaves_xrstors(&self) -> bool {
4708 self.eax1 & 0b1000 > 0
4709 }
4710
4711 pub fn xsave_size(&self) -> u32 {
4713 self.ebx1
4714 }
4715
4716 pub fn iter(&self) -> ExtendedStateIter<F> {
4718 ExtendedStateIter {
4719 read: self.read.clone(),
4720 level: 1,
4721 supported_xcr0: self.eax.bits(),
4722 supported_xss: self.ecx1.bits(),
4723 }
4724 }
4725}
4726
4727impl<R: CpuIdReader> Debug for ExtendedStateInfo<R> {
4728 fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
4729 f.debug_struct("ExtendedStateInfo")
4730 .field("eax", &self.eax)
4731 .field("ecx1", &self.ecx1)
4732 .field(
4733 "xsave_area_size_enabled_features",
4734 &self.xsave_area_size_enabled_features(),
4735 )
4736 .field(
4737 "xsave_area_size_supported_features",
4738 &self.xsave_area_size_supported_features(),
4739 )
4740 .field("has_xsaveopt", &self.has_xsaveopt())
4741 .field("has_xsavec", &self.has_xsavec())
4742 .field("has_xgetbv", &self.has_xgetbv())
4743 .field("has_xsaves_xrstors", &self.has_xsaves_xrstors())
4744 .field("xsave_size", &self.xsave_size())
4745 .field("extended_state_iter", &self.iter())
4746 .finish()
4747 }
4748}
4749
4750#[derive(Clone)]
4752pub struct ExtendedStateIter<R: CpuIdReader> {
4753 read: R,
4754 level: u32,
4755 supported_xcr0: u32,
4756 supported_xss: u32,
4757}
4758
4759impl<R: CpuIdReader> Iterator for ExtendedStateIter<R> {
4766 type Item = ExtendedState;
4767
4768 fn next(&mut self) -> Option<ExtendedState> {
4769 self.level += 1;
4770 if self.level > 31 {
4771 return None;
4772 }
4773
4774 let bit = 1 << self.level;
4775 if (self.supported_xcr0 & bit > 0) || (self.supported_xss & bit > 0) {
4776 let res = self.read.cpuid2(EAX_EXTENDED_STATE_INFO, self.level);
4777 return Some(ExtendedState {
4778 subleaf: self.level,
4779 eax: res.eax,
4780 ebx: res.ebx,
4781 ecx: res.ecx,
4782 });
4783 }
4784
4785 self.next()
4786 }
4787}
4788
4789impl<R: CpuIdReader> Debug for ExtendedStateIter<R> {
4790 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
4791 let mut debug = f.debug_list();
4792 self.clone().for_each(|ref item| {
4793 debug.entry(item);
4794 });
4795 debug.finish()
4796 }
4797}
4798
4799#[derive(PartialEq, Eq, Debug)]
4801#[repr(u32)]
4802pub enum ExtendedRegisterType {
4803 Avx,
4804 MpxBndregs,
4805 MpxBndcsr,
4806 Avx512Opmask,
4807 Avx512ZmmHi256,
4808 Avx512ZmmHi16,
4809 Pt,
4810 Pkru,
4811 Hdc,
4812 Unknown(u32),
4813}
4814
4815impl From<u32> for ExtendedRegisterType {
4816 fn from(value: u32) -> ExtendedRegisterType {
4817 match value {
4818 0x2 => ExtendedRegisterType::Avx,
4819 0x3 => ExtendedRegisterType::MpxBndregs,
4820 0x4 => ExtendedRegisterType::MpxBndcsr,
4821 0x5 => ExtendedRegisterType::Avx512Opmask,
4822 0x6 => ExtendedRegisterType::Avx512ZmmHi256,
4823 0x7 => ExtendedRegisterType::Avx512ZmmHi16,
4824 0x8 => ExtendedRegisterType::Pt,
4825 0x9 => ExtendedRegisterType::Pkru,
4826 0xd => ExtendedRegisterType::Hdc,
4827 x => ExtendedRegisterType::Unknown(x),
4828 }
4829 }
4830}
4831
4832impl fmt::Display for ExtendedRegisterType {
4833 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
4834 let data = match self {
4835 ExtendedRegisterType::Avx => "AVX/YMM",
4836 ExtendedRegisterType::MpxBndregs => "MPX BNDREGS",
4837 ExtendedRegisterType::MpxBndcsr => "MPX BNDCSR",
4838 ExtendedRegisterType::Avx512Opmask => "AVX-512 opmask",
4839 ExtendedRegisterType::Avx512ZmmHi256 => "AVX-512 ZMM_Hi256",
4840 ExtendedRegisterType::Avx512ZmmHi16 => "AVX-512 Hi16_ZMM",
4841 ExtendedRegisterType::Pkru => "PKRU",
4842 ExtendedRegisterType::Pt => "PT",
4843 ExtendedRegisterType::Hdc => "HDC",
4844 ExtendedRegisterType::Unknown(t) => {
4845 return write!(f, "Unknown({})", t);
4846 }
4847 };
4848
4849 f.write_str(data)
4850 }
4851}
4852
4853#[derive(PartialEq, Eq, Debug)]
4855pub enum ExtendedRegisterStateLocation {
4856 Xcr0,
4857 Ia32Xss,
4858}
4859
4860impl fmt::Display for ExtendedRegisterStateLocation {
4861 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
4862 let data = match self {
4863 ExtendedRegisterStateLocation::Xcr0 => "XCR0 (user state)",
4864 ExtendedRegisterStateLocation::Ia32Xss => "IA32_XSS (supervisor state)",
4865 };
4866
4867 f.write_str(data)
4868 }
4869}
4870
4871pub struct ExtendedState {
4873 pub subleaf: u32,
4874 eax: u32,
4875 ebx: u32,
4876 ecx: u32,
4877}
4878
4879impl ExtendedState {
4880 pub fn register(&self) -> ExtendedRegisterType {
4882 self.subleaf.into()
4883 }
4884
4885 pub fn size(&self) -> u32 {
4889 self.eax
4890 }
4891
4892 pub fn offset(&self) -> u32 {
4895 self.ebx
4896 }
4897
4898 pub fn location(&self) -> ExtendedRegisterStateLocation {
4899 if self.is_in_xcr0() {
4900 ExtendedRegisterStateLocation::Xcr0
4901 } else {
4902 ExtendedRegisterStateLocation::Ia32Xss
4903 }
4904 }
4905
4906 pub fn is_in_ia32_xss(&self) -> bool {
4912 self.ecx & 0b1 > 0
4913 }
4914
4915 pub fn is_in_xcr0(&self) -> bool {
4920 self.ecx & 0b1 == 0
4921 }
4922
4923 pub fn is_compacted_format(&self) -> bool {
4928 self.ecx & 0b10 > 0
4929 }
4930}
4931
4932impl Debug for ExtendedState {
4933 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
4934 f.debug_struct("ExtendedState")
4935 .field("size", &self.size())
4936 .field("offset", &self.offset())
4937 .field("is_in_ia32_xss", &self.is_in_ia32_xss())
4938 .field("is_in_xcr0", &self.is_in_xcr0())
4939 .field("is_compacted_format", &self.is_compacted_format())
4940 .finish()
4941 }
4942}
4943
4944pub struct RdtMonitoringInfo<R: CpuIdReader> {
4950 read: R,
4951 ebx: u32,
4952 edx: u32,
4953}
4954
4955impl<R: CpuIdReader> RdtMonitoringInfo<R> {
4956 pub fn rmid_range(&self) -> u32 {
4958 self.ebx
4959 }
4960
4961 check_bit_fn!(
4962 doc = "Supports L3 Cache Intel RDT Monitoring.",
4963 has_l3_monitoring,
4964 edx,
4965 1
4966 );
4967
4968 pub fn l3_monitoring(&self) -> Option<L3MonitoringInfo> {
4970 if self.has_l3_monitoring() {
4971 let res = self.read.cpuid2(EAX_RDT_MONITORING, 1);
4972 Some(L3MonitoringInfo {
4973 ebx: res.ebx,
4974 ecx: res.ecx,
4975 edx: res.edx,
4976 })
4977 } else {
4978 None
4979 }
4980 }
4981}
4982
4983impl<R: CpuIdReader> Debug for RdtMonitoringInfo<R> {
4984 fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
4985 f.debug_struct("RdtMonitoringInfo")
4986 .field("rmid_range", &self.rmid_range())
4987 .field("l3_monitoring", &self.l3_monitoring())
4988 .finish()
4989 }
4990}
4991
4992pub struct L3MonitoringInfo {
4994 ebx: u32,
4995 ecx: u32,
4996 edx: u32,
4997}
4998
4999impl L3MonitoringInfo {
5000 pub fn conversion_factor(&self) -> u32 {
5002 self.ebx
5003 }
5004
5005 pub fn maximum_rmid_range(&self) -> u32 {
5007 self.ecx
5008 }
5009
5010 check_bit_fn!(
5011 doc = "Supports occupancy monitoring.",
5012 has_occupancy_monitoring,
5013 edx,
5014 0
5015 );
5016
5017 check_bit_fn!(
5018 doc = "Supports total bandwidth monitoring.",
5019 has_total_bandwidth_monitoring,
5020 edx,
5021 1
5022 );
5023
5024 check_bit_fn!(
5025 doc = "Supports local bandwidth monitoring.",
5026 has_local_bandwidth_monitoring,
5027 edx,
5028 2
5029 );
5030}
5031
5032impl Debug for L3MonitoringInfo {
5033 fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
5034 f.debug_struct("L3MonitoringInfo")
5035 .field("conversion_factor", &self.conversion_factor())
5036 .field("maximum_rmid_range", &self.maximum_rmid_range())
5037 .finish()
5038 }
5039}
5040
5041pub struct RdtAllocationInfo<R: CpuIdReader> {
5046 read: R,
5047 ebx: u32,
5048}
5049
5050impl<R: CpuIdReader> RdtAllocationInfo<R> {
5051 check_bit_fn!(doc = "Supports L3 Cache Allocation.", has_l3_cat, ebx, 1);
5052
5053 check_bit_fn!(doc = "Supports L2 Cache Allocation.", has_l2_cat, ebx, 2);
5054
5055 check_bit_fn!(
5056 doc = "Supports Memory Bandwidth Allocation.",
5057 has_memory_bandwidth_allocation,
5058 ebx,
5059 3
5060 );
5061
5062 pub fn l3_cat(&self) -> Option<L3CatInfo> {
5064 if self.has_l3_cat() {
5065 let res = self.read.cpuid2(EAX_RDT_ALLOCATION, 1);
5066 Some(L3CatInfo {
5067 eax: res.eax,
5068 ebx: res.ebx,
5069 ecx: res.ecx,
5070 edx: res.edx,
5071 })
5072 } else {
5073 None
5074 }
5075 }
5076
5077 pub fn l2_cat(&self) -> Option<L2CatInfo> {
5079 if self.has_l2_cat() {
5080 let res = self.read.cpuid2(EAX_RDT_ALLOCATION, 2);
5081 Some(L2CatInfo {
5082 eax: res.eax,
5083 ebx: res.ebx,
5084 edx: res.edx,
5085 })
5086 } else {
5087 None
5088 }
5089 }
5090
5091 pub fn memory_bandwidth_allocation(&self) -> Option<MemBwAllocationInfo> {
5093 if self.has_memory_bandwidth_allocation() {
5094 let res = self.read.cpuid2(EAX_RDT_ALLOCATION, 3);
5095 Some(MemBwAllocationInfo {
5096 eax: res.eax,
5097 ecx: res.ecx,
5098 edx: res.edx,
5099 })
5100 } else {
5101 None
5102 }
5103 }
5104}
5105
5106impl<R: CpuIdReader> Debug for RdtAllocationInfo<R> {
5107 fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
5108 f.debug_struct("RdtAllocationInfo")
5109 .field("l3_cat", &self.l3_cat())
5110 .field("l2_cat", &self.l2_cat())
5111 .field(
5112 "memory_bandwidth_allocation",
5113 &self.memory_bandwidth_allocation(),
5114 )
5115 .finish()
5116 }
5117}
5118
5119pub struct L3CatInfo {
5121 eax: u32,
5122 ebx: u32,
5123 ecx: u32,
5124 edx: u32,
5125}
5126
5127impl L3CatInfo {
5128 pub fn capacity_mask_length(&self) -> u8 {
5130 (get_bits(self.eax, 0, 4) + 1) as u8
5131 }
5132
5133 pub fn isolation_bitmap(&self) -> u32 {
5135 self.ebx
5136 }
5137
5138 pub fn highest_cos(&self) -> u16 {
5140 get_bits(self.edx, 0, 15) as u16
5141 }
5142
5143 check_bit_fn!(
5144 doc = "Is Code and Data Prioritization Technology supported?",
5145 has_code_data_prioritization,
5146 ecx,
5147 2
5148 );
5149}
5150
5151impl Debug for L3CatInfo {
5152 fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
5153 f.debug_struct("L3CatInfo")
5154 .field("capacity_mask_length", &self.capacity_mask_length())
5155 .field("isolation_bitmap", &self.isolation_bitmap())
5156 .field("highest_cos", &self.highest_cos())
5157 .finish()
5158 }
5159}
5160
5161#[derive(Eq, PartialEq)]
5163pub struct L2CatInfo {
5164 eax: u32,
5165 ebx: u32,
5166 edx: u32,
5167}
5168
5169impl L2CatInfo {
5170 pub fn capacity_mask_length(&self) -> u8 {
5172 (get_bits(self.eax, 0, 4) + 1) as u8
5173 }
5174
5175 pub fn isolation_bitmap(&self) -> u32 {
5177 self.ebx
5178 }
5179
5180 pub fn highest_cos(&self) -> u16 {
5182 get_bits(self.edx, 0, 15) as u16
5183 }
5184}
5185
5186impl Debug for L2CatInfo {
5187 fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
5188 f.debug_struct("L2CatInfo")
5189 .field("capacity_mask_length", &self.capacity_mask_length())
5190 .field("isolation_bitmap", &self.isolation_bitmap())
5191 .field("highest_cos", &self.highest_cos())
5192 .finish()
5193 }
5194}
5195
5196#[derive(Eq, PartialEq)]
5198pub struct MemBwAllocationInfo {
5199 eax: u32,
5200 ecx: u32,
5201 edx: u32,
5202}
5203
5204impl MemBwAllocationInfo {
5205 pub fn max_hba_throttling(&self) -> u16 {
5207 (get_bits(self.eax, 0, 11) + 1) as u16
5208 }
5209
5210 pub fn highest_cos(&self) -> u16 {
5212 get_bits(self.edx, 0, 15) as u16
5213 }
5214
5215 check_bit_fn!(
5216 doc = "Reports whether the response of the delay values is linear.",
5217 has_linear_response_delay,
5218 ecx,
5219 2
5220 );
5221}
5222
5223impl Debug for MemBwAllocationInfo {
5224 fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
5225 f.debug_struct("MemBwAllocationInfo")
5226 .field("max_hba_throttling", &self.max_hba_throttling())
5227 .field("highest_cos", &self.highest_cos())
5228 .field(
5229 "has_linear_response_delay",
5230 &self.has_linear_response_delay(),
5231 )
5232 .finish()
5233 }
5234}
5235
5236pub struct SgxInfo<R: CpuIdReader> {
5243 read: R,
5244 eax: u32,
5245 ebx: u32,
5246 _ecx: u32,
5247 edx: u32,
5248 eax1: u32,
5249 ebx1: u32,
5250 ecx1: u32,
5251 edx1: u32,
5252}
5253
5254impl<F: CpuIdReader> SgxInfo<F> {
5255 check_bit_fn!(doc = "Has SGX1 support.", has_sgx1, eax, 0);
5256 check_bit_fn!(doc = "Has SGX2 support.", has_sgx2, eax, 1);
5257
5258 check_bit_fn!(
5259 doc = "Supports ENCLV instruction leaves EINCVIRTCHILD, EDECVIRTCHILD, and ESETCONTEXT.",
5260 has_enclv_leaves_einvirtchild_edecvirtchild_esetcontext,
5261 eax,
5262 5
5263 );
5264
5265 check_bit_fn!(
5266 doc = "Supports ENCLS instruction leaves ETRACKC, ERDINFO, ELDBC, and ELDUC.",
5267 has_encls_leaves_etrackc_erdinfo_eldbc_elduc,
5268 eax,
5269 6
5270 );
5271
5272 pub fn miscselect(&self) -> u32 {
5274 self.ebx
5275 }
5276
5277 pub fn max_enclave_size_non_64bit(&self) -> u8 {
5279 get_bits(self.edx, 0, 7) as u8
5280 }
5281
5282 pub fn max_enclave_size_64bit(&self) -> u8 {
5284 get_bits(self.edx, 8, 15) as u8
5285 }
5286
5287 pub fn secs_attributes(&self) -> (u64, u64) {
5289 let lower = self.eax1 as u64 | (self.ebx1 as u64) << 32;
5290 let upper = self.ecx1 as u64 | (self.edx1 as u64) << 32;
5291 (lower, upper)
5292 }
5293 pub fn iter(&self) -> SgxSectionIter<F> {
5295 SgxSectionIter {
5296 read: self.read.clone(),
5297 current: 2,
5298 }
5299 }
5300}
5301
5302impl<R: CpuIdReader> Debug for SgxInfo<R> {
5303 fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
5304 f.debug_struct("SgxInfo")
5305 .field("has_sgx1", &self.has_sgx1())
5306 .field("has_sgx2", &self.has_sgx2())
5307 .field("miscselect", &self.miscselect())
5308 .field(
5309 "max_enclave_size_non_64bit",
5310 &self.max_enclave_size_non_64bit(),
5311 )
5312 .field("max_enclave_size_64bit", &self.max_enclave_size_64bit())
5313 .field(
5314 "has_encls_leaves_etrackc_erdinfo_eldbc_elduc",
5315 &self.has_encls_leaves_etrackc_erdinfo_eldbc_elduc(),
5316 )
5317 .field(
5318 "has_enclv_leaves_einvirtchild_edecvirtchild_esetcontext",
5319 &self.has_enclv_leaves_einvirtchild_edecvirtchild_esetcontext(),
5320 )
5321 .field("sgx_section_iter", &self.iter())
5322 .finish()
5323 }
5324}
5325
5326#[derive(Clone)]
5328pub struct SgxSectionIter<R: CpuIdReader> {
5329 read: R,
5330 current: u32,
5331}
5332
5333impl<R: CpuIdReader> Iterator for SgxSectionIter<R> {
5334 type Item = SgxSectionInfo;
5335
5336 fn next(&mut self) -> Option<SgxSectionInfo> {
5337 let res = self.read.cpuid2(EAX_SGX, self.current);
5338 self.current += 1;
5339 match get_bits(res.eax, 0, 3) {
5340 0b0001 => Some(SgxSectionInfo::Epc(EpcSection {
5341 eax: res.eax,
5342 ebx: res.ebx,
5343 ecx: res.ecx,
5344 edx: res.edx,
5345 })),
5346 _ => None,
5347 }
5348 }
5349}
5350
5351impl<R: CpuIdReader> Debug for SgxSectionIter<R> {
5352 fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
5353 let mut debug = f.debug_list();
5354 self.clone().for_each(|ref item| {
5355 debug.entry(item);
5356 });
5357 debug.finish()
5358 }
5359}
5360
5361#[derive(Debug)]
5365pub enum SgxSectionInfo {
5366 Epc(EpcSection),
5368}
5369
5370#[derive(Debug)]
5372pub struct EpcSection {
5373 eax: u32,
5374 ebx: u32,
5375 ecx: u32,
5376 edx: u32,
5377}
5378
5379impl EpcSection {
5380 pub fn physical_base(&self) -> u64 {
5382 let lower = (get_bits(self.eax, 12, 31) << 12) as u64;
5383 let upper = (get_bits(self.ebx, 0, 19) as u64) << 32;
5384 lower | upper
5385 }
5386
5387 pub fn size(&self) -> u64 {
5389 let lower = (get_bits(self.ecx, 12, 31) << 12) as u64;
5390 let upper = (get_bits(self.edx, 0, 19) as u64) << 32;
5391 lower | upper
5392 }
5393}
5394
5395pub struct ProcessorTraceInfo {
5400 _eax: u32,
5401 ebx: u32,
5402 ecx: u32,
5403 _edx: u32,
5404 leaf1: Option<CpuIdResult>,
5405}
5406
5407impl ProcessorTraceInfo {
5408 check_bit_fn!(
5410 doc = "If true, Indicates that IA32_RTIT_CTL.CR3Filter can be set to 1, and \
5411 that IA32_RTIT_CR3_MATCH MSR can be accessed.",
5412 has_rtit_cr3_match,
5413 ebx,
5414 0
5415 );
5416 check_bit_fn!(
5417 doc = "If true, Indicates support of Configurable PSB and Cycle-Accurate Mode.",
5418 has_configurable_psb_and_cycle_accurate_mode,
5419 ebx,
5420 1
5421 );
5422 check_bit_fn!(
5423 doc = "If true, Indicates support of IP Filtering, TraceStop filtering, and \
5424 preservation of Intel PT MSRs across warm reset.",
5425 has_ip_tracestop_filtering,
5426 ebx,
5427 2
5428 );
5429 check_bit_fn!(
5430 doc = "If true, Indicates support of MTC timing packet and suppression of \
5431 COFI-based packets.",
5432 has_mtc_timing_packet_coefi_suppression,
5433 ebx,
5434 3
5435 );
5436
5437 check_bit_fn!(
5438 doc = "Indicates support of PTWRITE. Writes can set IA32_RTIT_CTL\\[12\\] (PTWEn \
5439 and IA32_RTIT_CTL\\[5\\] (FUPonPTW), and PTWRITE can generate packets",
5440 has_ptwrite,
5441 ebx,
5442 4
5443 );
5444
5445 check_bit_fn!(
5446 doc = "Support of Power Event Trace. Writes can set IA32_RTIT_CTL\\[4\\] (PwrEvtEn) \
5447 enabling Power Event Trace packet generation.",
5448 has_power_event_trace,
5449 ebx,
5450 5
5451 );
5452
5453 check_bit_fn!(
5455 doc = "If true, Tracing can be enabled with IA32_RTIT_CTL.ToPA = 1, hence \
5456 utilizing the ToPA output scheme; IA32_RTIT_OUTPUT_BASE and \
5457 IA32_RTIT_OUTPUT_MASK_PTRS MSRs can be accessed.",
5458 has_topa,
5459 ecx,
5460 0
5461 );
5462 check_bit_fn!(
5463 doc = "If true, ToPA tables can hold any number of output entries, up to the \
5464 maximum allowed by the MaskOrTableOffset field of \
5465 IA32_RTIT_OUTPUT_MASK_PTRS.",
5466 has_topa_maximum_entries,
5467 ecx,
5468 1
5469 );
5470 check_bit_fn!(
5471 doc = "If true, Indicates support of Single-Range Output scheme.",
5472 has_single_range_output_scheme,
5473 ecx,
5474 2
5475 );
5476 check_bit_fn!(
5477 doc = "If true, Indicates support of output to Trace Transport subsystem.",
5478 has_trace_transport_subsystem,
5479 ecx,
5480 3
5481 );
5482 check_bit_fn!(
5483 doc = "If true, Generated packets which contain IP payloads have LIP values, \
5484 which include the CS base component.",
5485 has_lip_with_cs_base,
5486 ecx,
5487 31
5488 );
5489
5490 pub fn configurable_address_ranges(&self) -> u8 {
5492 self.leaf1.map_or(0, |res| get_bits(res.eax, 0, 2) as u8)
5493 }
5494
5495 pub fn supported_mtc_period_encodings(&self) -> u16 {
5497 self.leaf1.map_or(0, |res| get_bits(res.eax, 16, 31) as u16)
5498 }
5499
5500 pub fn supported_cycle_threshold_value_encodings(&self) -> u16 {
5502 self.leaf1.map_or(0, |res| get_bits(res.ebx, 0, 15) as u16)
5503 }
5504
5505 pub fn supported_psb_frequency_encodings(&self) -> u16 {
5507 self.leaf1.map_or(0, |res| get_bits(res.ebx, 16, 31) as u16)
5508 }
5509}
5510
5511impl Debug for ProcessorTraceInfo {
5512 fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
5513 f.debug_struct("ProcessorTraceInfo")
5514 .field(
5515 "configurable_address_ranges",
5516 &self.configurable_address_ranges(),
5517 )
5518 .field(
5519 "supported_mtc_period_encodings",
5520 &self.supported_mtc_period_encodings(),
5521 )
5522 .field(
5523 "supported_cycle_threshold_value_encodings",
5524 &self.supported_cycle_threshold_value_encodings(),
5525 )
5526 .field(
5527 "supported_psb_frequency_encodings",
5528 &self.supported_psb_frequency_encodings(),
5529 )
5530 .finish()
5531 }
5532}
5533
5534pub struct TscInfo {
5539 eax: u32,
5540 ebx: u32,
5541 ecx: u32,
5542}
5543
5544impl fmt::Debug for TscInfo {
5545 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
5546 f.debug_struct("TscInfo")
5547 .field("denominator", &self.denominator())
5548 .field("numerator", &self.numerator())
5549 .field("nominal_frequency", &self.nominal_frequency())
5550 .field("tsc_frequency", &self.tsc_frequency())
5551 .finish()
5552 }
5553}
5554
5555impl TscInfo {
5556 pub fn denominator(&self) -> u32 {
5558 self.eax
5559 }
5560
5561 pub fn numerator(&self) -> u32 {
5565 self.ebx
5566 }
5567
5568 pub fn nominal_frequency(&self) -> u32 {
5572 self.ecx
5573 }
5574
5575 pub fn tsc_frequency(&self) -> Option<u64> {
5577 if self.nominal_frequency() == 0 || self.numerator() == 0 || self.denominator() == 0 {
5580 return None;
5581 }
5582
5583 Some(self.nominal_frequency() as u64 * self.numerator() as u64 / self.denominator() as u64)
5584 }
5585}
5586
5587pub struct ProcessorFrequencyInfo {
5592 eax: u32,
5593 ebx: u32,
5594 ecx: u32,
5595}
5596
5597impl ProcessorFrequencyInfo {
5598 pub fn processor_base_frequency(&self) -> u16 {
5600 get_bits(self.eax, 0, 15) as u16
5601 }
5602
5603 pub fn processor_max_frequency(&self) -> u16 {
5605 get_bits(self.ebx, 0, 15) as u16
5606 }
5607
5608 pub fn bus_frequency(&self) -> u16 {
5610 get_bits(self.ecx, 0, 15) as u16
5611 }
5612}
5613
5614impl fmt::Debug for ProcessorFrequencyInfo {
5615 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
5616 f.debug_struct("ProcessorFrequencyInfo")
5617 .field("processor_base_frequency", &self.processor_base_frequency())
5618 .field("processor_max_frequency", &self.processor_max_frequency())
5619 .field("bus_frequency", &self.bus_frequency())
5620 .finish()
5621 }
5622}
5623
5624#[derive(Clone)]
5629pub struct DatIter<R: CpuIdReader> {
5630 read: R,
5631 current: u32,
5632 count: u32,
5633}
5634
5635impl<R: CpuIdReader> Iterator for DatIter<R> {
5636 type Item = DatInfo;
5637
5638 fn next(&mut self) -> Option<DatInfo> {
5640 loop {
5641 if self.current > self.count {
5643 return None;
5644 }
5645
5646 let res = self
5647 .read
5648 .cpuid2(EAX_DETERMINISTIC_ADDRESS_TRANSLATION_INFO, self.current);
5649 self.current += 1;
5650
5651 if get_bits(res.edx, 0, 4) == 0 {
5653 continue;
5657 }
5658
5659 return Some(DatInfo {
5660 _eax: res.eax,
5661 ebx: res.ebx,
5662 ecx: res.ecx,
5663 edx: res.edx,
5664 });
5665 }
5666 }
5667}
5668
5669impl<R: CpuIdReader> Debug for DatIter<R> {
5670 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
5671 let mut debug = f.debug_list();
5672 self.clone().for_each(|ref item| {
5673 debug.entry(item);
5674 });
5675 debug.finish()
5676 }
5677}
5678
5679pub struct DatInfo {
5681 _eax: u32,
5682 ebx: u32,
5683 ecx: u32,
5684 edx: u32,
5685}
5686
5687impl DatInfo {
5688 check_bit_fn!(
5689 doc = "4K page size entries supported by this structure",
5690 has_4k_entries,
5691 ebx,
5692 0
5693 );
5694
5695 check_bit_fn!(
5696 doc = "2MB page size entries supported by this structure",
5697 has_2mb_entries,
5698 ebx,
5699 1
5700 );
5701
5702 check_bit_fn!(
5703 doc = "4MB page size entries supported by this structure",
5704 has_4mb_entries,
5705 ebx,
5706 2
5707 );
5708
5709 check_bit_fn!(
5710 doc = "1GB page size entries supported by this structure",
5711 has_1gb_entries,
5712 ebx,
5713 3
5714 );
5715
5716 check_bit_fn!(
5717 doc = "Fully associative structure",
5718 is_fully_associative,
5719 edx,
5720 8
5721 );
5722
5723 pub fn partitioning(&self) -> u8 {
5725 get_bits(self.ebx, 8, 10) as u8
5726 }
5727
5728 pub fn ways(&self) -> u16 {
5730 get_bits(self.ebx, 16, 31) as u16
5731 }
5732
5733 pub fn sets(&self) -> u32 {
5735 self.ecx
5736 }
5737
5738 pub fn cache_type(&self) -> DatType {
5740 match get_bits(self.edx, 0, 4) as u8 {
5741 0b00001 => DatType::DataTLB,
5742 0b00010 => DatType::InstructionTLB,
5743 0b00011 => DatType::UnifiedTLB,
5744 0b00000 => DatType::Null, 0b00100 => DatType::LoadOnly,
5746 0b00101 => DatType::StoreOnly,
5747 _ => DatType::Unknown,
5748 }
5749 }
5750
5751 pub fn cache_level(&self) -> u8 {
5753 get_bits(self.edx, 5, 7) as u8
5754 }
5755
5756 pub fn max_addressable_ids(&self) -> u16 {
5758 (get_bits(self.edx, 14, 25) + 1) as u16
5760 }
5761}
5762
5763impl Debug for DatInfo {
5764 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
5765 f.debug_struct("DatInfo")
5766 .field("has_4k_entries", &self.has_4k_entries())
5767 .field("has_2mb_entries", &self.has_2mb_entries())
5768 .field("has_4mb_entries", &self.has_4mb_entries())
5769 .field("has_1gb_entries", &self.has_1gb_entries())
5770 .field("is_fully_associative", &self.is_fully_associative())
5771 .finish()
5772 }
5773}
5774
5775#[derive(Eq, PartialEq, Debug)]
5777pub enum DatType {
5778 Null = 0b00000,
5780 DataTLB = 0b00001,
5781 InstructionTLB = 0b00010,
5782 UnifiedTLB = 0b00011,
5788 LoadOnly = 0b0100,
5789 StoreOnly = 0b0101,
5790 Unknown,
5791}
5792
5793impl fmt::Display for DatType {
5794 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
5795 let t = match self {
5796 DatType::Null => "invalid (0)",
5797 DatType::DataTLB => "Data TLB",
5798 DatType::InstructionTLB => "Instruction TLB",
5799 DatType::UnifiedTLB => "Unified TLB",
5800 DatType::LoadOnly => "Load Only",
5801 DatType::StoreOnly => "Store Only",
5802 DatType::Unknown => "Unknown",
5803 };
5804 f.write_str(t)
5805 }
5806}
5807
5808pub struct SoCVendorInfo<R: CpuIdReader> {
5813 read: R,
5814 eax: u32,
5816 ebx: u32,
5817 ecx: u32,
5818 edx: u32,
5819}
5820
5821impl<R: CpuIdReader> SoCVendorInfo<R> {
5822 pub fn get_soc_vendor_id(&self) -> u16 {
5823 get_bits(self.ebx, 0, 15) as u16
5824 }
5825
5826 pub fn get_project_id(&self) -> u32 {
5827 self.ecx
5828 }
5829
5830 pub fn get_stepping_id(&self) -> u32 {
5831 self.edx
5832 }
5833
5834 pub fn get_vendor_brand(&self) -> Option<SoCVendorBrand> {
5835 if self.eax >= 3 {
5837 let r1 = self.read.cpuid2(EAX_SOC_VENDOR_INFO, 1);
5838 let r2 = self.read.cpuid2(EAX_SOC_VENDOR_INFO, 2);
5839 let r3 = self.read.cpuid2(EAX_SOC_VENDOR_INFO, 3);
5840 Some(SoCVendorBrand { data: [r1, r2, r3] })
5841 } else {
5842 None
5843 }
5844 }
5845
5846 pub fn get_vendor_attributes(&self) -> Option<SoCVendorAttributesIter<R>> {
5847 if self.eax > 3 {
5848 Some(SoCVendorAttributesIter {
5849 read: self.read.clone(),
5850 count: self.eax,
5851 current: 3,
5852 })
5853 } else {
5854 None
5855 }
5856 }
5857}
5858
5859impl<R: CpuIdReader> fmt::Debug for SoCVendorInfo<R> {
5860 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
5861 f.debug_struct("SoCVendorInfo")
5862 .field("soc_vendor_id", &self.get_soc_vendor_id())
5863 .field("project_id", &self.get_project_id())
5864 .field("stepping_id", &self.get_stepping_id())
5865 .field("vendor_brand", &self.get_vendor_brand())
5866 .field("vendor_attributes", &self.get_vendor_attributes())
5867 .finish()
5868 }
5869}
5870
5871pub struct SoCVendorAttributesIter<R: CpuIdReader> {
5873 read: R,
5874 count: u32,
5875 current: u32,
5876}
5877
5878impl<R: CpuIdReader> fmt::Debug for SoCVendorAttributesIter<R> {
5879 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
5880 f.debug_struct("SocVendorAttributesIter")
5881 .field("count", &self.count)
5882 .field("current", &self.current)
5883 .finish()
5884 }
5885}
5886
5887impl<R: CpuIdReader> Iterator for SoCVendorAttributesIter<R> {
5888 type Item = CpuIdResult;
5889
5890 fn next(&mut self) -> Option<CpuIdResult> {
5892 if self.current > self.count {
5893 return None;
5894 }
5895 self.count += 1;
5896 Some(self.read.cpuid2(EAX_SOC_VENDOR_INFO, self.count))
5897 }
5898}
5899
5900#[derive(Debug, PartialEq, Eq)]
5902#[repr(C)]
5903pub struct SoCVendorBrand {
5904 data: [CpuIdResult; 3],
5905}
5906
5907impl SoCVendorBrand {
5908 pub fn as_str(&self) -> &str {
5910 let brand_string_start = self as *const SoCVendorBrand as *const u8;
5911 let slice = unsafe {
5912 slice::from_raw_parts(brand_string_start, size_of::<SoCVendorBrand>())
5914 };
5915 str::from_utf8(slice).unwrap_or("InvalidSoCVendorString")
5916 }
5917
5918 #[deprecated(
5919 since = "10.0.0",
5920 note = "Use idiomatic function name `as_str` instead"
5921 )]
5922 pub fn as_string(&self) -> &str {
5923 self.as_str()
5924 }
5925}
5926
5927impl fmt::Display for SoCVendorBrand {
5928 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
5929 write!(f, "{}", self.as_str())
5930 }
5931}
5932
5933pub struct HypervisorInfo<R: CpuIdReader> {
5938 read: R,
5939 res: CpuIdResult,
5940}
5941
5942impl<R: CpuIdReader> fmt::Debug for HypervisorInfo<R> {
5943 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
5944 f.debug_struct("HypervisorInfo")
5945 .field("identify", &self.identify())
5946 .field("tsc_frequency", &self.tsc_frequency())
5947 .field("apic_frequency", &self.apic_frequency())
5948 .finish()
5949 }
5950}
5951
5952#[derive(Debug, Eq, PartialEq)]
5954pub enum Hypervisor {
5955 Xen,
5956 VMware,
5957 HyperV,
5958 KVM,
5959 QEMU,
5962 Bhyve,
5963 QNX,
5964 ACRN,
5965 Unknown(u32, u32, u32),
5966}
5967
5968impl<R: CpuIdReader> HypervisorInfo<R> {
5969 pub fn identify(&self) -> Hypervisor {
5980 match (self.res.ebx, self.res.ecx, self.res.edx) {
5981 (0x61774d56, 0x4d566572, 0x65726177) => Hypervisor::VMware,
5983 (0x566e6558, 0x65584d4d, 0x4d4d566e) => Hypervisor::Xen,
5985 (0x7263694d, 0x666f736f, 0x76482074) => Hypervisor::HyperV,
5987 (0x4b4d564b, 0x564b4d56, 0x0000004d) => Hypervisor::KVM,
5989 (0x54474354, 0x43544743, 0x47435447) => Hypervisor::QEMU,
5992 (0x76796862, 0x68622065, 0x20657679) => Hypervisor::Bhyve,
5995 (0x56794842, 0x48422045, 0x20455679) => Hypervisor::Bhyve,
5999 (0x51584e51, 0x53424d56, 0x00004751) => Hypervisor::QNX,
6003 (0x4e524341, 0x4e524341, 0x4e524341) => Hypervisor::ACRN,
6005 (ebx, ecx, edx) => Hypervisor::Unknown(ebx, ecx, edx),
6006 }
6007 }
6008
6009 pub fn tsc_frequency(&self) -> Option<u32> {
6011 if self.res.eax >= 0x40000010 {
6014 let virt_tinfo = self.read.cpuid2(0x40000010, 0);
6015 Some(virt_tinfo.eax)
6016 } else {
6017 None
6018 }
6019 }
6020
6021 pub fn apic_frequency(&self) -> Option<u32> {
6023 if self.res.eax >= 0x40000010 {
6025 let virt_tinfo = self.read.cpuid2(0x40000010, 0);
6026 Some(virt_tinfo.ebx)
6027 } else {
6028 None
6029 }
6030 }
6031}
6032
6033#[cfg(doctest)]
6034mod test_readme {
6035 macro_rules! external_doc_test {
6036 ($x:expr) => {
6037 #[doc = $x]
6038 extern "C" {}
6039 };
6040 }
6041
6042 external_doc_test!(include_str!("../README.md"));
6043}