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" => 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_CACHE_PARAMETERS_AMD: u32 = 0x8000_001D;
323const EAX_PROCESSOR_TOPOLOGY_INFO: u32 = 0x8000_001E;
324const EAX_MEMORY_ENCRYPTION_INFO: u32 = 0x8000_001F;
325const EAX_SVM_FEATURES: u32 = 0x8000_000A;
326
327impl<R: CpuIdReader> CpuId<R> {
328 pub fn with_cpuid_reader(cpuid_fn: R) -> Self {
333 let vendor_leaf = cpuid_fn.cpuid1(EAX_VENDOR_INFO);
334 let extended_leaf = cpuid_fn.cpuid1(EAX_EXTENDED_FUNCTION_INFO);
335 CpuId {
336 supported_leafs: vendor_leaf.eax,
337 supported_extended_leafs: extended_leaf.eax,
338 vendor: Vendor::from_vendor_leaf(vendor_leaf),
339 read: cpuid_fn,
340 }
341 }
342
343 pub fn with_cpuid_fn(cpuid_fn: R) -> Self {
349 CpuId::with_cpuid_reader(cpuid_fn)
350 }
351
352 fn leaf_is_supported(&self, val: u32) -> bool {
354 if self.vendor == Vendor::Amd && ((0x2..=0x4).contains(&val) || (0x8..=0xa).contains(&val))
356 {
357 return false;
358 }
359
360 if val < EAX_EXTENDED_FUNCTION_INFO {
361 val <= self.supported_leafs
362 } else {
363 val <= self.supported_extended_leafs
364 }
365 }
366
367 pub fn get_vendor_info(&self) -> Option<VendorInfo> {
375 if self.leaf_is_supported(EAX_VENDOR_INFO) {
376 let res = self.read.cpuid1(EAX_VENDOR_INFO);
377 Some(VendorInfo {
378 ebx: res.ebx,
379 ecx: res.ecx,
380 edx: res.edx,
381 })
382 } else {
383 None
384 }
385 }
386
387 pub fn get_feature_info(&self) -> Option<FeatureInfo> {
392 if self.leaf_is_supported(EAX_FEATURE_INFO) {
393 let res = self.read.cpuid1(EAX_FEATURE_INFO);
394 Some(FeatureInfo {
395 vendor: self.vendor,
396 eax: res.eax,
397 ebx: res.ebx,
398 edx_ecx: FeatureInfoFlags::from_bits_truncate(
399 ((res.edx as u64) << 32) | (res.ecx as u64),
400 ),
401 })
402 } else {
403 None
404 }
405 }
406
407 pub fn get_cache_info(&self) -> Option<CacheInfoIter> {
412 if self.leaf_is_supported(EAX_CACHE_INFO) {
413 let res = self.read.cpuid1(EAX_CACHE_INFO);
414 Some(CacheInfoIter {
415 current: 1,
416 eax: res.eax,
417 ebx: res.ebx,
418 ecx: res.ecx,
419 edx: res.edx,
420 })
421 } else {
422 None
423 }
424 }
425
426 pub fn get_processor_serial(&self) -> Option<ProcessorSerial> {
431 if self.leaf_is_supported(EAX_PROCESSOR_SERIAL) {
432 let res1 = self.read.cpuid1(EAX_FEATURE_INFO);
434 let res = self.read.cpuid1(EAX_PROCESSOR_SERIAL);
435 Some(ProcessorSerial {
436 ecx: res.ecx,
437 edx: res.edx,
438 eax: res1.eax,
439 })
440 } else {
441 None
442 }
443 }
444
445 pub fn get_cache_parameters(&self) -> Option<CacheParametersIter<R>> {
454 if self.leaf_is_supported(EAX_CACHE_PARAMETERS)
455 || (self.vendor == Vendor::Amd && self.leaf_is_supported(EAX_CACHE_PARAMETERS_AMD))
456 {
457 Some(CacheParametersIter {
458 read: self.read.clone(),
459 leaf: if self.vendor == Vendor::Amd {
460 EAX_CACHE_PARAMETERS_AMD
461 } else {
462 EAX_CACHE_PARAMETERS
463 },
464 current: 0,
465 })
466 } else {
467 None
468 }
469 }
470
471 pub fn get_monitor_mwait_info(&self) -> Option<MonitorMwaitInfo> {
476 if self.leaf_is_supported(EAX_MONITOR_MWAIT_INFO) {
477 let res = self.read.cpuid1(EAX_MONITOR_MWAIT_INFO);
478 Some(MonitorMwaitInfo {
479 eax: res.eax,
480 ebx: res.ebx,
481 ecx: res.ecx,
482 edx: res.edx,
483 })
484 } else {
485 None
486 }
487 }
488
489 pub fn get_thermal_power_info(&self) -> Option<ThermalPowerInfo> {
494 if self.leaf_is_supported(EAX_THERMAL_POWER_INFO) {
495 let res = self.read.cpuid1(EAX_THERMAL_POWER_INFO);
496 Some(ThermalPowerInfo {
497 eax: ThermalPowerFeaturesEax::from_bits_truncate(res.eax),
498 ebx: res.ebx,
499 ecx: ThermalPowerFeaturesEcx::from_bits_truncate(res.ecx),
500 _edx: res.edx,
501 })
502 } else {
503 None
504 }
505 }
506
507 pub fn get_extended_feature_info(&self) -> Option<ExtendedFeatures> {
512 if self.leaf_is_supported(EAX_STRUCTURED_EXTENDED_FEATURE_INFO) {
513 let res = self.read.cpuid1(EAX_STRUCTURED_EXTENDED_FEATURE_INFO);
514 Some(ExtendedFeatures {
515 _eax: res.eax,
516 ebx: ExtendedFeaturesEbx::from_bits_truncate(res.ebx),
517 ecx: ExtendedFeaturesEcx::from_bits_truncate(res.ecx),
518 edx: ExtendedFeaturesEdx::from_bits_truncate(res.edx),
519 })
520 } else {
521 None
522 }
523 }
524
525 pub fn get_direct_cache_access_info(&self) -> Option<DirectCacheAccessInfo> {
530 if self.leaf_is_supported(EAX_DIRECT_CACHE_ACCESS_INFO) {
531 let res = self.read.cpuid1(EAX_DIRECT_CACHE_ACCESS_INFO);
532 Some(DirectCacheAccessInfo { eax: res.eax })
533 } else {
534 None
535 }
536 }
537
538 pub fn get_performance_monitoring_info(&self) -> Option<PerformanceMonitoringInfo> {
543 if self.leaf_is_supported(EAX_PERFORMANCE_MONITOR_INFO) {
544 let res = self.read.cpuid1(EAX_PERFORMANCE_MONITOR_INFO);
545 Some(PerformanceMonitoringInfo {
546 eax: res.eax,
547 ebx: PerformanceMonitoringFeaturesEbx::from_bits_truncate(res.ebx),
548 _ecx: res.ecx,
549 edx: res.edx,
550 })
551 } else {
552 None
553 }
554 }
555
556 pub fn get_extended_topology_info(&self) -> Option<ExtendedTopologyIter<R>> {
565 if self.leaf_is_supported(EAX_EXTENDED_TOPOLOGY_INFO) {
566 Some(ExtendedTopologyIter {
567 read: self.read.clone(),
568 level: 0,
569 is_v2: false,
570 })
571 } else {
572 None
573 }
574 }
575
576 pub fn get_extended_topology_info_v2(&self) -> Option<ExtendedTopologyIter<R>> {
581 if self.leaf_is_supported(EAX_EXTENDED_TOPOLOGY_INFO_V2) {
582 Some(ExtendedTopologyIter {
583 read: self.read.clone(),
584 level: 0,
585 is_v2: true,
586 })
587 } else {
588 None
589 }
590 }
591
592 pub fn get_extended_state_info(&self) -> Option<ExtendedStateInfo<R>> {
597 if self.leaf_is_supported(EAX_EXTENDED_STATE_INFO) {
598 let res = self.read.cpuid2(EAX_EXTENDED_STATE_INFO, 0);
599 let res1 = self.read.cpuid2(EAX_EXTENDED_STATE_INFO, 1);
600 Some(ExtendedStateInfo {
601 read: self.read.clone(),
602 eax: ExtendedStateInfoXCR0Flags::from_bits_truncate(res.eax),
603 ebx: res.ebx,
604 ecx: res.ecx,
605 _edx: res.edx,
606 eax1: res1.eax,
607 ebx1: res1.ebx,
608 ecx1: ExtendedStateInfoXSSFlags::from_bits_truncate(res1.ecx),
609 _edx1: res1.edx,
610 })
611 } else {
612 None
613 }
614 }
615
616 pub fn get_rdt_monitoring_info(&self) -> Option<RdtMonitoringInfo<R>> {
621 let res = self.read.cpuid1(EAX_RDT_MONITORING);
622
623 if self.leaf_is_supported(EAX_RDT_MONITORING) {
624 Some(RdtMonitoringInfo {
625 read: self.read.clone(),
626 ebx: res.ebx,
627 edx: res.edx,
628 })
629 } else {
630 None
631 }
632 }
633
634 pub fn get_rdt_allocation_info(&self) -> Option<RdtAllocationInfo<R>> {
639 let res = self.read.cpuid1(EAX_RDT_ALLOCATION);
640
641 if self.leaf_is_supported(EAX_RDT_ALLOCATION) {
642 Some(RdtAllocationInfo {
643 read: self.read.clone(),
644 ebx: res.ebx,
645 })
646 } else {
647 None
648 }
649 }
650
651 pub fn get_sgx_info(&self) -> Option<SgxInfo<R>> {
656 self.get_extended_feature_info().and_then(|info| {
658 if self.leaf_is_supported(EAX_SGX) && info.has_sgx() {
659 let res = self.read.cpuid2(EAX_SGX, 0);
660 let res1 = self.read.cpuid2(EAX_SGX, 1);
661 Some(SgxInfo {
662 read: self.read.clone(),
663 eax: res.eax,
664 ebx: res.ebx,
665 _ecx: res.ecx,
666 edx: res.edx,
667 eax1: res1.eax,
668 ebx1: res1.ebx,
669 ecx1: res1.ecx,
670 edx1: res1.edx,
671 })
672 } else {
673 None
674 }
675 })
676 }
677
678 pub fn get_processor_trace_info(&self) -> Option<ProcessorTraceInfo> {
683 if self.leaf_is_supported(EAX_TRACE_INFO) {
684 let res = self.read.cpuid2(EAX_TRACE_INFO, 0);
685 let res1 = if res.eax >= 1 {
686 Some(self.read.cpuid2(EAX_TRACE_INFO, 1))
687 } else {
688 None
689 };
690
691 Some(ProcessorTraceInfo {
692 _eax: res.eax,
693 ebx: res.ebx,
694 ecx: res.ecx,
695 _edx: res.edx,
696 leaf1: res1,
697 })
698 } else {
699 None
700 }
701 }
702
703 pub fn get_tsc_info(&self) -> Option<TscInfo> {
708 if self.leaf_is_supported(EAX_TIME_STAMP_COUNTER_INFO) {
709 let res = self.read.cpuid2(EAX_TIME_STAMP_COUNTER_INFO, 0);
710 Some(TscInfo {
711 eax: res.eax,
712 ebx: res.ebx,
713 ecx: res.ecx,
714 })
715 } else {
716 None
717 }
718 }
719
720 pub fn get_processor_frequency_info(&self) -> Option<ProcessorFrequencyInfo> {
725 if self.leaf_is_supported(EAX_FREQUENCY_INFO) {
726 let res = self.read.cpuid1(EAX_FREQUENCY_INFO);
727 Some(ProcessorFrequencyInfo {
728 eax: res.eax,
729 ebx: res.ebx,
730 ecx: res.ecx,
731 })
732 } else {
733 None
734 }
735 }
736
737 pub fn get_soc_vendor_info(&self) -> Option<SoCVendorInfo<R>> {
742 if self.leaf_is_supported(EAX_SOC_VENDOR_INFO) {
743 let res = self.read.cpuid1(EAX_SOC_VENDOR_INFO);
744 Some(SoCVendorInfo {
745 read: self.read.clone(),
746 eax: res.eax,
747 ebx: res.ebx,
748 ecx: res.ecx,
749 edx: res.edx,
750 })
751 } else {
752 None
753 }
754 }
755
756 pub fn get_deterministic_address_translation_info(&self) -> Option<DatIter<R>> {
761 if self.leaf_is_supported(EAX_DETERMINISTIC_ADDRESS_TRANSLATION_INFO) {
762 let res = self
763 .read
764 .cpuid2(EAX_DETERMINISTIC_ADDRESS_TRANSLATION_INFO, 0);
765 Some(DatIter {
766 read: self.read.clone(),
767 current: 0,
768 count: res.eax,
769 })
770 } else {
771 None
772 }
773 }
774
775 pub fn get_hypervisor_info(&self) -> Option<HypervisorInfo<R>> {
781 self.get_feature_info()
784 .filter(|fi| fi.has_hypervisor())
785 .and_then(|_| {
786 let res = self.read.cpuid1(EAX_HYPERVISOR_INFO);
787 if res.eax > 0 {
788 Some(HypervisorInfo {
789 read: self.read.clone(),
790 res,
791 })
792 } else {
793 None
794 }
795 })
796 }
797
798 pub fn get_extended_processor_and_feature_identifiers(
803 &self,
804 ) -> Option<ExtendedProcessorFeatureIdentifiers> {
805 if self.leaf_is_supported(EAX_EXTENDED_PROCESSOR_AND_FEATURE_IDENTIFIERS) {
806 Some(ExtendedProcessorFeatureIdentifiers::new(
807 self.vendor,
808 self.read
809 .cpuid1(EAX_EXTENDED_PROCESSOR_AND_FEATURE_IDENTIFIERS),
810 ))
811 } else {
812 None
813 }
814 }
815
816 pub fn get_processor_brand_string(&self) -> Option<ProcessorBrandString> {
821 if self.leaf_is_supported(EAX_EXTENDED_BRAND_STRING)
822 && self.leaf_is_supported(EAX_EXTENDED_BRAND_STRING + 1)
823 && self.leaf_is_supported(EAX_EXTENDED_BRAND_STRING + 2)
824 {
825 Some(ProcessorBrandString::new([
826 self.read.cpuid1(EAX_EXTENDED_BRAND_STRING),
827 self.read.cpuid1(EAX_EXTENDED_BRAND_STRING + 1),
828 self.read.cpuid1(EAX_EXTENDED_BRAND_STRING + 2),
829 ]))
830 } else {
831 None
832 }
833 }
834
835 pub fn get_l1_cache_and_tlb_info(&self) -> Option<L1CacheTlbInfo> {
840 if self.vendor == Vendor::Amd && self.leaf_is_supported(EAX_L1_CACHE_INFO) {
841 Some(L1CacheTlbInfo::new(self.read.cpuid1(EAX_L1_CACHE_INFO)))
842 } else {
843 None
844 }
845 }
846
847 pub fn get_l2_l3_cache_and_tlb_info(&self) -> Option<L2And3CacheTlbInfo> {
852 if self.leaf_is_supported(EAX_L2_L3_CACHE_INFO) {
853 Some(L2And3CacheTlbInfo::new(
854 self.read.cpuid1(EAX_L2_L3_CACHE_INFO),
855 ))
856 } else {
857 None
858 }
859 }
860
861 pub fn get_advanced_power_mgmt_info(&self) -> Option<ApmInfo> {
866 if self.leaf_is_supported(EAX_ADVANCED_POWER_MGMT_INFO) {
867 Some(ApmInfo::new(self.read.cpuid1(EAX_ADVANCED_POWER_MGMT_INFO)))
868 } else {
869 None
870 }
871 }
872
873 pub fn get_processor_capacity_feature_info(&self) -> Option<ProcessorCapacityAndFeatureInfo> {
878 if self.leaf_is_supported(EAX_PROCESSOR_CAPACITY_INFO) {
879 Some(ProcessorCapacityAndFeatureInfo::new(
880 self.read.cpuid1(EAX_PROCESSOR_CAPACITY_INFO),
881 ))
882 } else {
883 None
884 }
885 }
886
887 pub fn get_svm_info(&self) -> Option<SvmFeatures> {
896 let has_svm = self
897 .get_extended_processor_and_feature_identifiers()
898 .map_or(false, |f| f.has_svm());
899 if has_svm && self.leaf_is_supported(EAX_SVM_FEATURES) {
900 Some(SvmFeatures::new(self.read.cpuid1(EAX_SVM_FEATURES)))
901 } else {
902 None
903 }
904 }
905
906 pub fn get_tlb_1gb_page_info(&self) -> Option<Tlb1gbPageInfo> {
911 if self.leaf_is_supported(EAX_TLB_1GB_PAGE_INFO) {
912 Some(Tlb1gbPageInfo::new(self.read.cpuid1(EAX_TLB_1GB_PAGE_INFO)))
913 } else {
914 None
915 }
916 }
917
918 pub fn get_performance_optimization_info(&self) -> Option<PerformanceOptimizationInfo> {
923 if self.leaf_is_supported(EAX_PERFORMANCE_OPTIMIZATION_INFO) {
924 Some(PerformanceOptimizationInfo::new(
925 self.read.cpuid1(EAX_PERFORMANCE_OPTIMIZATION_INFO),
926 ))
927 } else {
928 None
929 }
930 }
931
932 pub fn get_processor_topology_info(&self) -> Option<ProcessorTopologyInfo> {
937 if self.leaf_is_supported(EAX_PROCESSOR_TOPOLOGY_INFO) {
938 Some(ProcessorTopologyInfo::new(
939 self.read.cpuid1(EAX_PROCESSOR_TOPOLOGY_INFO),
940 ))
941 } else {
942 None
943 }
944 }
945
946 pub fn get_memory_encryption_info(&self) -> Option<MemoryEncryptionInfo> {
951 if self.leaf_is_supported(EAX_MEMORY_ENCRYPTION_INFO) {
952 Some(MemoryEncryptionInfo::new(
953 self.read.cpuid1(EAX_MEMORY_ENCRYPTION_INFO),
954 ))
955 } else {
956 None
957 }
958 }
959}
960
961impl<R: CpuIdReader> Debug for CpuId<R> {
962 fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
963 f.debug_struct("CpuId")
964 .field("vendor", &self.vendor)
965 .field("vendor_info", &self.get_vendor_info())
968 .field("feature_info", &self.get_feature_info())
969 .field("cache_info", &self.get_cache_info())
970 .field("processor_serial", &self.get_processor_serial())
971 .field("cache_parameters", &self.get_cache_parameters())
972 .field("monitor_mwait_info", &self.get_monitor_mwait_info())
973 .field("thermal_power_info", &self.get_thermal_power_info())
974 .field("extended_feature_info", &self.get_extended_feature_info())
975 .field(
976 "direct_cache_access_info",
977 &self.get_direct_cache_access_info(),
978 )
979 .field(
980 "performance_monitoring_info",
981 &self.get_performance_monitoring_info(),
982 )
983 .field("extended_topology_info", &self.get_extended_topology_info())
984 .field("extended_state_info", &self.get_extended_state_info())
985 .field("rdt_monitoring_info", &self.get_rdt_monitoring_info())
986 .field("rdt_allocation_info", &self.get_rdt_allocation_info())
987 .field("sgx_info", &self.get_sgx_info())
988 .field("processor_trace_info", &self.get_processor_trace_info())
989 .field("tsc_info", &self.get_tsc_info())
990 .field(
991 "processor_frequency_info",
992 &self.get_processor_frequency_info(),
993 )
994 .field(
995 "deterministic_address_translation_info",
996 &self.get_deterministic_address_translation_info(),
997 )
998 .field("soc_vendor_info", &self.get_soc_vendor_info())
999 .field("hypervisor_info", &self.get_hypervisor_info())
1000 .field(
1001 "extended_processor_and_feature_identifiers",
1002 &self.get_extended_processor_and_feature_identifiers(),
1003 )
1004 .field("processor_brand_string", &self.get_processor_brand_string())
1005 .field("l1_cache_and_tlb_info", &self.get_l1_cache_and_tlb_info())
1006 .field(
1007 "l2_l3_cache_and_tlb_info",
1008 &self.get_l2_l3_cache_and_tlb_info(),
1009 )
1010 .field(
1011 "advanced_power_mgmt_info",
1012 &self.get_advanced_power_mgmt_info(),
1013 )
1014 .field(
1015 "processor_capacity_feature_info",
1016 &self.get_processor_capacity_feature_info(),
1017 )
1018 .field("svm_info", &self.get_svm_info())
1019 .field("tlb_1gb_page_info", &self.get_tlb_1gb_page_info())
1020 .field(
1021 "performance_optimization_info",
1022 &self.get_performance_optimization_info(),
1023 )
1024 .field(
1025 "processor_topology_info",
1026 &self.get_processor_topology_info(),
1027 )
1028 .field("memory_encryption_info", &self.get_memory_encryption_info())
1029 .finish()
1030 }
1031}
1032
1033#[derive(PartialEq, Eq)]
1045#[repr(C)]
1046pub struct VendorInfo {
1047 ebx: u32,
1048 edx: u32,
1049 ecx: u32,
1050}
1051
1052impl VendorInfo {
1053 pub fn as_str(&self) -> &str {
1055 let brand_string_start = self as *const VendorInfo as *const u8;
1056 let slice = unsafe {
1057 slice::from_raw_parts(brand_string_start, size_of::<VendorInfo>())
1060 };
1061
1062 str::from_utf8(slice).unwrap_or("InvalidVendorString")
1063 }
1064
1065 #[deprecated(
1066 since = "10.0.0",
1067 note = "Use idiomatic function name `as_str` instead"
1068 )]
1069 pub fn as_string(&self) -> &str {
1070 self.as_str()
1071 }
1072}
1073
1074impl Debug for VendorInfo {
1075 fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
1076 f.debug_struct("VendorInfo")
1077 .field("brand_string", &self.as_str())
1078 .finish()
1079 }
1080}
1081
1082impl fmt::Display for VendorInfo {
1083 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1084 write!(f, "{}", self.as_str())
1085 }
1086}
1087
1088#[derive(PartialEq, Eq, Clone)]
1096pub struct CacheInfoIter {
1097 current: u32,
1098 eax: u32,
1099 ebx: u32,
1100 ecx: u32,
1101 edx: u32,
1102}
1103
1104impl Iterator for CacheInfoIter {
1105 type Item = CacheInfo;
1106
1107 fn next(&mut self) -> Option<CacheInfo> {
1109 if self.current >= 4 * 4 {
1113 return None;
1114 }
1115 let reg_index = self.current % 4;
1116 let byte_index = self.current / 4;
1117
1118 let reg = match reg_index {
1119 0 => self.eax,
1120 1 => self.ebx,
1121 2 => self.ecx,
1122 3 => self.edx,
1123 _ => unreachable!(),
1124 };
1125
1126 let byte = match byte_index {
1127 0 => reg,
1128 1 => reg >> 8,
1129 2 => reg >> 16,
1130 3 => reg >> 24,
1131 _ => unreachable!(),
1132 } as u8;
1133
1134 if byte == 0 {
1135 self.current += 1;
1136 return self.next();
1137 }
1138
1139 for cache_info in CACHE_INFO_TABLE.iter() {
1140 if cache_info.num == byte {
1141 self.current += 1;
1142 return Some(*cache_info);
1143 }
1144 }
1145
1146 None
1147 }
1148}
1149
1150impl Debug for CacheInfoIter {
1151 fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
1152 let mut debug = f.debug_list();
1153 self.clone().for_each(|ref item| {
1154 debug.entry(item);
1155 });
1156 debug.finish()
1157 }
1158}
1159
1160#[derive(Copy, Clone, Debug)]
1162pub enum CacheInfoType {
1163 General,
1164 Cache,
1165 TLB,
1166 STLB,
1167 DTLB,
1168 Prefetch,
1169}
1170
1171#[derive(Copy, Clone)]
1173pub struct CacheInfo {
1174 pub num: u8,
1176 pub typ: CacheInfoType,
1178}
1179
1180impl CacheInfo {
1181 pub fn desc(&self) -> &'static str {
1183 match self.num {
1184 0x00 => "Null descriptor, this byte contains no information",
1185 0x01 => "Instruction TLB: 4 KByte pages, 4-way set associative, 32 entries",
1186 0x02 => "Instruction TLB: 4 MByte pages, fully associative, 2 entries",
1187 0x03 => "Data TLB: 4 KByte pages, 4-way set associative, 64 entries",
1188 0x04 => "Data TLB: 4 MByte pages, 4-way set associative, 8 entries",
1189 0x05 => "Data TLB1: 4 MByte pages, 4-way set associative, 32 entries",
1190 0x06 => "1st-level instruction cache: 8 KBytes, 4-way set associative, 32 byte line size",
1191 0x08 => "1st-level instruction cache: 16 KBytes, 4-way set associative, 32 byte line size",
1192 0x09 => "1st-level instruction cache: 32KBytes, 4-way set associative, 64 byte line size",
1193 0x0A => "1st-level data cache: 8 KBytes, 2-way set associative, 32 byte line size",
1194 0x0B => "Instruction TLB: 4 MByte pages, 4-way set associative, 4 entries",
1195 0x0C => "1st-level data cache: 16 KBytes, 4-way set associative, 32 byte line size",
1196 0x0D => "1st-level data cache: 16 KBytes, 4-way set associative, 64 byte line size",
1197 0x0E => "1st-level data cache: 24 KBytes, 6-way set associative, 64 byte line size",
1198 0x1D => "2nd-level cache: 128 KBytes, 2-way set associative, 64 byte line size",
1199 0x21 => "2nd-level cache: 256 KBytes, 8-way set associative, 64 byte line size",
1200 0x22 => "3rd-level cache: 512 KBytes, 4-way set associative, 64 byte line size, 2 lines per sector",
1201 0x23 => "3rd-level cache: 1 MBytes, 8-way set associative, 64 byte line size, 2 lines per sector",
1202 0x24 => "2nd-level cache: 1 MBytes, 16-way set associative, 64 byte line size",
1203 0x25 => "3rd-level cache: 2 MBytes, 8-way set associative, 64 byte line size, 2 lines per sector",
1204 0x29 => "3rd-level cache: 4 MBytes, 8-way set associative, 64 byte line size, 2 lines per sector",
1205 0x2C => "1st-level data cache: 32 KBytes, 8-way set associative, 64 byte line size",
1206 0x30 => "1st-level instruction cache: 32 KBytes, 8-way set associative, 64 byte line size",
1207 0x40 => "No 2nd-level cache or, if processor contains a valid 2nd-level cache, no 3rd-level cache",
1208 0x41 => "2nd-level cache: 128 KBytes, 4-way set associative, 32 byte line size",
1209 0x42 => "2nd-level cache: 256 KBytes, 4-way set associative, 32 byte line size",
1210 0x43 => "2nd-level cache: 512 KBytes, 4-way set associative, 32 byte line size",
1211 0x44 => "2nd-level cache: 1 MByte, 4-way set associative, 32 byte line size",
1212 0x45 => "2nd-level cache: 2 MByte, 4-way set associative, 32 byte line size",
1213 0x46 => "3rd-level cache: 4 MByte, 4-way set associative, 64 byte line size",
1214 0x47 => "3rd-level cache: 8 MByte, 8-way set associative, 64 byte line size",
1215 0x48 => "2nd-level cache: 3MByte, 12-way set associative, 64 byte line size",
1216 0x49 => "3rd-level cache: 4MB, 16-way set associative, 64-byte line size (Intel Xeon processor MP, Family 0FH, Model 06H); 2nd-level cache: 4 MByte, 16-way set ssociative, 64 byte line size",
1217 0x4A => "3rd-level cache: 6MByte, 12-way set associative, 64 byte line size",
1218 0x4B => "3rd-level cache: 8MByte, 16-way set associative, 64 byte line size",
1219 0x4C => "3rd-level cache: 12MByte, 12-way set associative, 64 byte line size",
1220 0x4D => "3rd-level cache: 16MByte, 16-way set associative, 64 byte line size",
1221 0x4E => "2nd-level cache: 6MByte, 24-way set associative, 64 byte line size",
1222 0x4F => "Instruction TLB: 4 KByte pages, 32 entries",
1223 0x50 => "Instruction TLB: 4 KByte and 2-MByte or 4-MByte pages, 64 entries",
1224 0x51 => "Instruction TLB: 4 KByte and 2-MByte or 4-MByte pages, 128 entries",
1225 0x52 => "Instruction TLB: 4 KByte and 2-MByte or 4-MByte pages, 256 entries",
1226 0x55 => "Instruction TLB: 2-MByte or 4-MByte pages, fully associative, 7 entries",
1227 0x56 => "Data TLB0: 4 MByte pages, 4-way set associative, 16 entries",
1228 0x57 => "Data TLB0: 4 KByte pages, 4-way associative, 16 entries",
1229 0x59 => "Data TLB0: 4 KByte pages, fully associative, 16 entries",
1230 0x5A => "Data TLB0: 2-MByte or 4 MByte pages, 4-way set associative, 32 entries",
1231 0x5B => "Data TLB: 4 KByte and 4 MByte pages, 64 entries",
1232 0x5C => "Data TLB: 4 KByte and 4 MByte pages,128 entries",
1233 0x5D => "Data TLB: 4 KByte and 4 MByte pages,256 entries",
1234 0x60 => "1st-level data cache: 16 KByte, 8-way set associative, 64 byte line size",
1235 0x61 => "Instruction TLB: 4 KByte pages, fully associative, 48 entries",
1236 0x63 => "Data TLB: 2 MByte or 4 MByte pages, 4-way set associative, 32 entries and a separate array with 1 GByte pages, 4-way set associative, 4 entries",
1237 0x64 => "Data TLB: 4 KByte pages, 4-way set associative, 512 entries",
1238 0x66 => "1st-level data cache: 8 KByte, 4-way set associative, 64 byte line size",
1239 0x67 => "1st-level data cache: 16 KByte, 4-way set associative, 64 byte line size",
1240 0x68 => "1st-level data cache: 32 KByte, 4-way set associative, 64 byte line size",
1241 0x6A => "uTLB: 4 KByte pages, 8-way set associative, 64 entries",
1242 0x6B => "DTLB: 4 KByte pages, 8-way set associative, 256 entries",
1243 0x6C => "DTLB: 2M/4M pages, 8-way set associative, 128 entries",
1244 0x6D => "DTLB: 1 GByte pages, fully associative, 16 entries",
1245 0x70 => "Trace cache: 12 K-μop, 8-way set associative",
1246 0x71 => "Trace cache: 16 K-μop, 8-way set associative",
1247 0x72 => "Trace cache: 32 K-μop, 8-way set associative",
1248 0x76 => "Instruction TLB: 2M/4M pages, fully associative, 8 entries",
1249 0x78 => "2nd-level cache: 1 MByte, 4-way set associative, 64byte line size",
1250 0x79 => "2nd-level cache: 128 KByte, 8-way set associative, 64 byte line size, 2 lines per sector",
1251 0x7A => "2nd-level cache: 256 KByte, 8-way set associative, 64 byte line size, 2 lines per sector",
1252 0x7B => "2nd-level cache: 512 KByte, 8-way set associative, 64 byte line size, 2 lines per sector",
1253 0x7C => "2nd-level cache: 1 MByte, 8-way set associative, 64 byte line size, 2 lines per sector",
1254 0x7D => "2nd-level cache: 2 MByte, 8-way set associative, 64byte line size",
1255 0x7F => "2nd-level cache: 512 KByte, 2-way set associative, 64-byte line size",
1256 0x80 => "2nd-level cache: 512 KByte, 8-way set associative, 64-byte line size",
1257 0x82 => "2nd-level cache: 256 KByte, 8-way set associative, 32 byte line size",
1258 0x83 => "2nd-level cache: 512 KByte, 8-way set associative, 32 byte line size",
1259 0x84 => "2nd-level cache: 1 MByte, 8-way set associative, 32 byte line size",
1260 0x85 => "2nd-level cache: 2 MByte, 8-way set associative, 32 byte line size",
1261 0x86 => "2nd-level cache: 512 KByte, 4-way set associative, 64 byte line size",
1262 0x87 => "2nd-level cache: 1 MByte, 8-way set associative, 64 byte line size",
1263 0xA0 => "DTLB: 4k pages, fully associative, 32 entries",
1264 0xB0 => "Instruction TLB: 4 KByte pages, 4-way set associative, 128 entries",
1265 0xB1 => "Instruction TLB: 2M pages, 4-way, 8 entries or 4M pages, 4-way, 4 entries",
1266 0xB2 => "Instruction TLB: 4KByte pages, 4-way set associative, 64 entries",
1267 0xB3 => "Data TLB: 4 KByte pages, 4-way set associative, 128 entries",
1268 0xB4 => "Data TLB1: 4 KByte pages, 4-way associative, 256 entries",
1269 0xB5 => "Instruction TLB: 4KByte pages, 8-way set associative, 64 entries",
1270 0xB6 => "Instruction TLB: 4KByte pages, 8-way set associative, 128 entries",
1271 0xBA => "Data TLB1: 4 KByte pages, 4-way associative, 64 entries",
1272 0xC0 => "Data TLB: 4 KByte and 4 MByte pages, 4-way associative, 8 entries",
1273 0xC1 => "Shared 2nd-Level TLB: 4 KByte/2MByte pages, 8-way associative, 1024 entries",
1274 0xC2 => "DTLB: 2 MByte/$MByte pages, 4-way associative, 16 entries",
1275 0xC3 => "Shared 2nd-Level TLB: 4 KByte /2 MByte pages, 6-way associative, 1536 entries. Also 1GBbyte pages, 4-way, 16 entries.",
1276 0xC4 => "DTLB: 2M/4M Byte pages, 4-way associative, 32 entries",
1277 0xCA => "Shared 2nd-Level TLB: 4 KByte pages, 4-way associative, 512 entries",
1278 0xD0 => "3rd-level cache: 512 KByte, 4-way set associative, 64 byte line size",
1279 0xD1 => "3rd-level cache: 1 MByte, 4-way set associative, 64 byte line size",
1280 0xD2 => "3rd-level cache: 2 MByte, 4-way set associative, 64 byte line size",
1281 0xD6 => "3rd-level cache: 1 MByte, 8-way set associative, 64 byte line size",
1282 0xD7 => "3rd-level cache: 2 MByte, 8-way set associative, 64 byte line size",
1283 0xD8 => "3rd-level cache: 4 MByte, 8-way set associative, 64 byte line size",
1284 0xDC => "3rd-level cache: 1.5 MByte, 12-way set associative, 64 byte line size",
1285 0xDD => "3rd-level cache: 3 MByte, 12-way set associative, 64 byte line size",
1286 0xDE => "3rd-level cache: 6 MByte, 12-way set associative, 64 byte line size",
1287 0xE2 => "3rd-level cache: 2 MByte, 16-way set associative, 64 byte line size",
1288 0xE3 => "3rd-level cache: 4 MByte, 16-way set associative, 64 byte line size",
1289 0xE4 => "3rd-level cache: 8 MByte, 16-way set associative, 64 byte line size",
1290 0xEA => "3rd-level cache: 12MByte, 24-way set associative, 64 byte line size",
1291 0xEB => "3rd-level cache: 18MByte, 24-way set associative, 64 byte line size",
1292 0xEC => "3rd-level cache: 24MByte, 24-way set associative, 64 byte line size",
1293 0xF0 => "64-Byte prefetching",
1294 0xF1 => "128-Byte prefetching",
1295 0xFE => "CPUID leaf 2 does not report TLB descriptor information; use CPUID leaf 18H to query TLB and other address translation parameters.",
1296 0xFF => "CPUID leaf 2 does not report cache descriptor information, use CPUID leaf 4 to query cache parameters",
1297 _ => "Unknown cache type!"
1298 }
1299 }
1300}
1301
1302impl Debug for CacheInfo {
1303 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
1304 f.debug_struct("CacheInfo")
1305 .field("typ", &self.typ)
1306 .field("desc", &self.desc())
1307 .finish()
1308 }
1309}
1310
1311impl fmt::Display for CacheInfo {
1312 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1313 let typ = match self.typ {
1314 CacheInfoType::General => "N/A",
1315 CacheInfoType::Cache => "Cache",
1316 CacheInfoType::TLB => "TLB",
1317 CacheInfoType::STLB => "STLB",
1318 CacheInfoType::DTLB => "DTLB",
1319 CacheInfoType::Prefetch => "Prefetcher",
1320 };
1321
1322 write!(f, "{:x}:\t {}: {}", self.num, typ, self.desc())
1323 }
1324}
1325
1326pub const CACHE_INFO_TABLE: [CacheInfo; 108] = [
1328 CacheInfo {
1329 num: 0x00,
1330 typ: CacheInfoType::General,
1331 },
1332 CacheInfo {
1333 num: 0x01,
1334 typ: CacheInfoType::TLB,
1335 },
1336 CacheInfo {
1337 num: 0x02,
1338 typ: CacheInfoType::TLB,
1339 },
1340 CacheInfo {
1341 num: 0x03,
1342 typ: CacheInfoType::TLB,
1343 },
1344 CacheInfo {
1345 num: 0x04,
1346 typ: CacheInfoType::TLB,
1347 },
1348 CacheInfo {
1349 num: 0x05,
1350 typ: CacheInfoType::TLB,
1351 },
1352 CacheInfo {
1353 num: 0x06,
1354 typ: CacheInfoType::Cache,
1355 },
1356 CacheInfo {
1357 num: 0x08,
1358 typ: CacheInfoType::Cache,
1359 },
1360 CacheInfo {
1361 num: 0x09,
1362 typ: CacheInfoType::Cache,
1363 },
1364 CacheInfo {
1365 num: 0x0A,
1366 typ: CacheInfoType::Cache,
1367 },
1368 CacheInfo {
1369 num: 0x0B,
1370 typ: CacheInfoType::TLB,
1371 },
1372 CacheInfo {
1373 num: 0x0C,
1374 typ: CacheInfoType::Cache,
1375 },
1376 CacheInfo {
1377 num: 0x0D,
1378 typ: CacheInfoType::Cache,
1379 },
1380 CacheInfo {
1381 num: 0x0E,
1382 typ: CacheInfoType::Cache,
1383 },
1384 CacheInfo {
1385 num: 0x21,
1386 typ: CacheInfoType::Cache,
1387 },
1388 CacheInfo {
1389 num: 0x22,
1390 typ: CacheInfoType::Cache,
1391 },
1392 CacheInfo {
1393 num: 0x23,
1394 typ: CacheInfoType::Cache,
1395 },
1396 CacheInfo {
1397 num: 0x24,
1398 typ: CacheInfoType::Cache,
1399 },
1400 CacheInfo {
1401 num: 0x25,
1402 typ: CacheInfoType::Cache,
1403 },
1404 CacheInfo {
1405 num: 0x29,
1406 typ: CacheInfoType::Cache,
1407 },
1408 CacheInfo {
1409 num: 0x2C,
1410 typ: CacheInfoType::Cache,
1411 },
1412 CacheInfo {
1413 num: 0x30,
1414 typ: CacheInfoType::Cache,
1415 },
1416 CacheInfo {
1417 num: 0x40,
1418 typ: CacheInfoType::Cache,
1419 },
1420 CacheInfo {
1421 num: 0x41,
1422 typ: CacheInfoType::Cache,
1423 },
1424 CacheInfo {
1425 num: 0x42,
1426 typ: CacheInfoType::Cache,
1427 },
1428 CacheInfo {
1429 num: 0x43,
1430 typ: CacheInfoType::Cache,
1431 },
1432 CacheInfo {
1433 num: 0x44,
1434 typ: CacheInfoType::Cache,
1435 },
1436 CacheInfo {
1437 num: 0x45,
1438 typ: CacheInfoType::Cache,
1439 },
1440 CacheInfo {
1441 num: 0x46,
1442 typ: CacheInfoType::Cache,
1443 },
1444 CacheInfo {
1445 num: 0x47,
1446 typ: CacheInfoType::Cache,
1447 },
1448 CacheInfo {
1449 num: 0x48,
1450 typ: CacheInfoType::Cache,
1451 },
1452 CacheInfo {
1453 num: 0x49,
1454 typ: CacheInfoType::Cache,
1455 },
1456 CacheInfo {
1457 num: 0x4A,
1458 typ: CacheInfoType::Cache,
1459 },
1460 CacheInfo {
1461 num: 0x4B,
1462 typ: CacheInfoType::Cache,
1463 },
1464 CacheInfo {
1465 num: 0x4C,
1466 typ: CacheInfoType::Cache,
1467 },
1468 CacheInfo {
1469 num: 0x4D,
1470 typ: CacheInfoType::Cache,
1471 },
1472 CacheInfo {
1473 num: 0x4E,
1474 typ: CacheInfoType::Cache,
1475 },
1476 CacheInfo {
1477 num: 0x4F,
1478 typ: CacheInfoType::TLB,
1479 },
1480 CacheInfo {
1481 num: 0x50,
1482 typ: CacheInfoType::TLB,
1483 },
1484 CacheInfo {
1485 num: 0x51,
1486 typ: CacheInfoType::TLB,
1487 },
1488 CacheInfo {
1489 num: 0x52,
1490 typ: CacheInfoType::TLB,
1491 },
1492 CacheInfo {
1493 num: 0x55,
1494 typ: CacheInfoType::TLB,
1495 },
1496 CacheInfo {
1497 num: 0x56,
1498 typ: CacheInfoType::TLB,
1499 },
1500 CacheInfo {
1501 num: 0x57,
1502 typ: CacheInfoType::TLB,
1503 },
1504 CacheInfo {
1505 num: 0x59,
1506 typ: CacheInfoType::TLB,
1507 },
1508 CacheInfo {
1509 num: 0x5A,
1510 typ: CacheInfoType::TLB,
1511 },
1512 CacheInfo {
1513 num: 0x5B,
1514 typ: CacheInfoType::TLB,
1515 },
1516 CacheInfo {
1517 num: 0x5C,
1518 typ: CacheInfoType::TLB,
1519 },
1520 CacheInfo {
1521 num: 0x5D,
1522 typ: CacheInfoType::TLB,
1523 },
1524 CacheInfo {
1525 num: 0x60,
1526 typ: CacheInfoType::Cache,
1527 },
1528 CacheInfo {
1529 num: 0x61,
1530 typ: CacheInfoType::TLB,
1531 },
1532 CacheInfo {
1533 num: 0x63,
1534 typ: CacheInfoType::TLB,
1535 },
1536 CacheInfo {
1537 num: 0x66,
1538 typ: CacheInfoType::Cache,
1539 },
1540 CacheInfo {
1541 num: 0x67,
1542 typ: CacheInfoType::Cache,
1543 },
1544 CacheInfo {
1545 num: 0x68,
1546 typ: CacheInfoType::Cache,
1547 },
1548 CacheInfo {
1549 num: 0x6A,
1550 typ: CacheInfoType::Cache,
1551 },
1552 CacheInfo {
1553 num: 0x6B,
1554 typ: CacheInfoType::Cache,
1555 },
1556 CacheInfo {
1557 num: 0x6C,
1558 typ: CacheInfoType::Cache,
1559 },
1560 CacheInfo {
1561 num: 0x6D,
1562 typ: CacheInfoType::Cache,
1563 },
1564 CacheInfo {
1565 num: 0x70,
1566 typ: CacheInfoType::Cache,
1567 },
1568 CacheInfo {
1569 num: 0x71,
1570 typ: CacheInfoType::Cache,
1571 },
1572 CacheInfo {
1573 num: 0x72,
1574 typ: CacheInfoType::Cache,
1575 },
1576 CacheInfo {
1577 num: 0x76,
1578 typ: CacheInfoType::TLB,
1579 },
1580 CacheInfo {
1581 num: 0x78,
1582 typ: CacheInfoType::Cache,
1583 },
1584 CacheInfo {
1585 num: 0x79,
1586 typ: CacheInfoType::Cache,
1587 },
1588 CacheInfo {
1589 num: 0x7A,
1590 typ: CacheInfoType::Cache,
1591 },
1592 CacheInfo {
1593 num: 0x7B,
1594 typ: CacheInfoType::Cache,
1595 },
1596 CacheInfo {
1597 num: 0x7C,
1598 typ: CacheInfoType::Cache,
1599 },
1600 CacheInfo {
1601 num: 0x7D,
1602 typ: CacheInfoType::Cache,
1603 },
1604 CacheInfo {
1605 num: 0x7F,
1606 typ: CacheInfoType::Cache,
1607 },
1608 CacheInfo {
1609 num: 0x80,
1610 typ: CacheInfoType::Cache,
1611 },
1612 CacheInfo {
1613 num: 0x82,
1614 typ: CacheInfoType::Cache,
1615 },
1616 CacheInfo {
1617 num: 0x83,
1618 typ: CacheInfoType::Cache,
1619 },
1620 CacheInfo {
1621 num: 0x84,
1622 typ: CacheInfoType::Cache,
1623 },
1624 CacheInfo {
1625 num: 0x85,
1626 typ: CacheInfoType::Cache,
1627 },
1628 CacheInfo {
1629 num: 0x86,
1630 typ: CacheInfoType::Cache,
1631 },
1632 CacheInfo {
1633 num: 0x87,
1634 typ: CacheInfoType::Cache,
1635 },
1636 CacheInfo {
1637 num: 0xB0,
1638 typ: CacheInfoType::TLB,
1639 },
1640 CacheInfo {
1641 num: 0xB1,
1642 typ: CacheInfoType::TLB,
1643 },
1644 CacheInfo {
1645 num: 0xB2,
1646 typ: CacheInfoType::TLB,
1647 },
1648 CacheInfo {
1649 num: 0xB3,
1650 typ: CacheInfoType::TLB,
1651 },
1652 CacheInfo {
1653 num: 0xB4,
1654 typ: CacheInfoType::TLB,
1655 },
1656 CacheInfo {
1657 num: 0xB5,
1658 typ: CacheInfoType::TLB,
1659 },
1660 CacheInfo {
1661 num: 0xB6,
1662 typ: CacheInfoType::TLB,
1663 },
1664 CacheInfo {
1665 num: 0xBA,
1666 typ: CacheInfoType::TLB,
1667 },
1668 CacheInfo {
1669 num: 0xC0,
1670 typ: CacheInfoType::TLB,
1671 },
1672 CacheInfo {
1673 num: 0xC1,
1674 typ: CacheInfoType::STLB,
1675 },
1676 CacheInfo {
1677 num: 0xC2,
1678 typ: CacheInfoType::DTLB,
1679 },
1680 CacheInfo {
1681 num: 0xCA,
1682 typ: CacheInfoType::STLB,
1683 },
1684 CacheInfo {
1685 num: 0xD0,
1686 typ: CacheInfoType::Cache,
1687 },
1688 CacheInfo {
1689 num: 0xD1,
1690 typ: CacheInfoType::Cache,
1691 },
1692 CacheInfo {
1693 num: 0xD2,
1694 typ: CacheInfoType::Cache,
1695 },
1696 CacheInfo {
1697 num: 0xD6,
1698 typ: CacheInfoType::Cache,
1699 },
1700 CacheInfo {
1701 num: 0xD7,
1702 typ: CacheInfoType::Cache,
1703 },
1704 CacheInfo {
1705 num: 0xD8,
1706 typ: CacheInfoType::Cache,
1707 },
1708 CacheInfo {
1709 num: 0xDC,
1710 typ: CacheInfoType::Cache,
1711 },
1712 CacheInfo {
1713 num: 0xDD,
1714 typ: CacheInfoType::Cache,
1715 },
1716 CacheInfo {
1717 num: 0xDE,
1718 typ: CacheInfoType::Cache,
1719 },
1720 CacheInfo {
1721 num: 0xE2,
1722 typ: CacheInfoType::Cache,
1723 },
1724 CacheInfo {
1725 num: 0xE3,
1726 typ: CacheInfoType::Cache,
1727 },
1728 CacheInfo {
1729 num: 0xE4,
1730 typ: CacheInfoType::Cache,
1731 },
1732 CacheInfo {
1733 num: 0xEA,
1734 typ: CacheInfoType::Cache,
1735 },
1736 CacheInfo {
1737 num: 0xEB,
1738 typ: CacheInfoType::Cache,
1739 },
1740 CacheInfo {
1741 num: 0xEC,
1742 typ: CacheInfoType::Cache,
1743 },
1744 CacheInfo {
1745 num: 0xF0,
1746 typ: CacheInfoType::Prefetch,
1747 },
1748 CacheInfo {
1749 num: 0xF1,
1750 typ: CacheInfoType::Prefetch,
1751 },
1752 CacheInfo {
1753 num: 0xFE,
1754 typ: CacheInfoType::General,
1755 },
1756 CacheInfo {
1757 num: 0xFF,
1758 typ: CacheInfoType::General,
1759 },
1760];
1761
1762#[derive(PartialEq, Eq)]
1773pub struct ProcessorSerial {
1774 ecx: u32,
1776 edx: u32,
1778 eax: u32,
1780}
1781
1782impl ProcessorSerial {
1783 pub fn serial_lower(&self) -> u32 {
1787 self.ecx
1788 }
1789
1790 pub fn serial_middle(&self) -> u32 {
1794 self.edx
1795 }
1796
1797 pub fn serial_upper(&self) -> u32 {
1799 self.eax
1800 }
1801
1802 pub fn serial(&self) -> u64 {
1804 (self.serial_lower() as u64) | (self.serial_middle() as u64) << 32
1805 }
1806
1807 pub fn serial_all(&self) -> u128 {
1809 (self.serial_lower() as u128)
1810 | ((self.serial_middle() as u128) << 32)
1811 | ((self.serial_upper() as u128) << 64)
1812 }
1813}
1814
1815impl Debug for ProcessorSerial {
1816 fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
1817 f.debug_struct("ProcessorSerial")
1818 .field("serial_lower", &self.serial_lower())
1819 .field("serial_middle", &self.serial_middle())
1820 .finish()
1821 }
1822}
1823
1824pub struct FeatureInfo {
1829 vendor: Vendor,
1830 eax: u32,
1831 ebx: u32,
1832 edx_ecx: FeatureInfoFlags,
1833}
1834
1835impl FeatureInfo {
1836 pub fn extended_family_id(&self) -> u8 {
1838 get_bits(self.eax, 20, 27) as u8
1839 }
1840
1841 pub fn extended_model_id(&self) -> u8 {
1843 get_bits(self.eax, 16, 19) as u8
1844 }
1845
1846 pub fn base_family_id(&self) -> u8 {
1848 get_bits(self.eax, 8, 11) as u8
1849 }
1850
1851 pub fn base_model_id(&self) -> u8 {
1853 get_bits(self.eax, 4, 7) as u8
1854 }
1855
1856 pub fn family_id(&self) -> u8 {
1857 let base_family_id = self.base_family_id();
1858 let extended_family_id = self.extended_family_id();
1859 let just_use_base = (self.vendor == Vendor::Amd && base_family_id < 0xf)
1860 || (self.vendor == Vendor::Intel && base_family_id != 0xf);
1861
1862 if just_use_base {
1863 base_family_id
1864 } else {
1865 base_family_id + extended_family_id
1866 }
1867 }
1868
1869 pub fn model_id(&self) -> u8 {
1870 let base_family_id = self.base_family_id();
1871 let base_model_id = self.base_model_id();
1872 let extended_model_id = self.extended_model_id();
1873 let just_use_base = (self.vendor == Vendor::Amd && base_family_id < 0xf)
1874 || (self.vendor == Vendor::Intel && base_family_id != 0xf && base_family_id != 0x6);
1875
1876 if just_use_base {
1877 base_model_id
1878 } else {
1879 (extended_model_id << 4) | base_model_id
1880 }
1881 }
1882
1883 pub fn stepping_id(&self) -> u8 {
1885 get_bits(self.eax, 0, 3) as u8
1886 }
1887
1888 pub fn brand_index(&self) -> u8 {
1890 get_bits(self.ebx, 0, 7) as u8
1891 }
1892
1893 pub fn cflush_cache_line_size(&self) -> u8 {
1895 get_bits(self.ebx, 8, 15) as u8
1896 }
1897
1898 pub fn initial_local_apic_id(&self) -> u8 {
1900 get_bits(self.ebx, 24, 31) as u8
1901 }
1902
1903 pub fn max_logical_processor_ids(&self) -> u8 {
1905 get_bits(self.ebx, 16, 23) as u8
1906 }
1907
1908 check_flag!(
1909 doc = "Streaming SIMD Extensions 3 (SSE3). A value of 1 indicates the processor \
1910 supports this technology.",
1911 has_sse3,
1912 edx_ecx,
1913 FeatureInfoFlags::SSE3
1914 );
1915
1916 check_flag!(
1917 doc = "PCLMULQDQ. A value of 1 indicates the processor supports the PCLMULQDQ \
1918 instruction",
1919 has_pclmulqdq,
1920 edx_ecx,
1921 FeatureInfoFlags::PCLMULQDQ
1922 );
1923
1924 check_flag!(
1925 doc = "64-bit DS Area. A value of 1 indicates the processor supports DS area \
1926 using 64-bit layout",
1927 has_ds_area,
1928 edx_ecx,
1929 FeatureInfoFlags::DTES64
1930 );
1931
1932 check_flag!(
1933 doc = "MONITOR/MWAIT. A value of 1 indicates the processor supports this feature.",
1934 has_monitor_mwait,
1935 edx_ecx,
1936 FeatureInfoFlags::MONITOR
1937 );
1938
1939 check_flag!(
1940 doc = "CPL Qualified Debug Store. A value of 1 indicates the processor supports \
1941 the extensions to the Debug Store feature to allow for branch message \
1942 storage qualified by CPL.",
1943 has_cpl,
1944 edx_ecx,
1945 FeatureInfoFlags::DSCPL
1946 );
1947
1948 check_flag!(
1949 doc = "Virtual Machine Extensions. A value of 1 indicates that the processor \
1950 supports this technology.",
1951 has_vmx,
1952 edx_ecx,
1953 FeatureInfoFlags::VMX
1954 );
1955
1956 check_flag!(
1957 doc = "Safer Mode Extensions. A value of 1 indicates that the processor supports \
1958 this technology. See Chapter 5, Safer Mode Extensions Reference.",
1959 has_smx,
1960 edx_ecx,
1961 FeatureInfoFlags::SMX
1962 );
1963
1964 check_flag!(
1965 doc = "Enhanced Intel SpeedStep® technology. A value of 1 indicates that the \
1966 processor supports this technology.",
1967 has_eist,
1968 edx_ecx,
1969 FeatureInfoFlags::EIST
1970 );
1971
1972 check_flag!(
1973 doc = "Thermal Monitor 2. A value of 1 indicates whether the processor supports \
1974 this technology.",
1975 has_tm2,
1976 edx_ecx,
1977 FeatureInfoFlags::TM2
1978 );
1979
1980 check_flag!(
1981 doc = "A value of 1 indicates the presence of the Supplemental Streaming SIMD \
1982 Extensions 3 (SSSE3). A value of 0 indicates the instruction extensions \
1983 are not present in the processor",
1984 has_ssse3,
1985 edx_ecx,
1986 FeatureInfoFlags::SSSE3
1987 );
1988
1989 check_flag!(
1990 doc = "L1 Context ID. A value of 1 indicates the L1 data cache mode can be set \
1991 to either adaptive mode or shared mode. A value of 0 indicates this \
1992 feature is not supported. See definition of the IA32_MISC_ENABLE MSR Bit \
1993 24 (L1 Data Cache Context Mode) for details.",
1994 has_cnxtid,
1995 edx_ecx,
1996 FeatureInfoFlags::CNXTID
1997 );
1998
1999 check_flag!(
2000 doc = "A value of 1 indicates the processor supports FMA extensions using YMM \
2001 state.",
2002 has_fma,
2003 edx_ecx,
2004 FeatureInfoFlags::FMA
2005 );
2006
2007 check_flag!(
2008 doc = "CMPXCHG16B Available. A value of 1 indicates that the feature is \
2009 available. See the CMPXCHG8B/CMPXCHG16B Compare and Exchange Bytes \
2010 section. 14",
2011 has_cmpxchg16b,
2012 edx_ecx,
2013 FeatureInfoFlags::CMPXCHG16B
2014 );
2015
2016 check_flag!(
2017 doc = "Perfmon and Debug Capability: A value of 1 indicates the processor \
2018 supports the performance and debug feature indication MSR \
2019 IA32_PERF_CAPABILITIES.",
2020 has_pdcm,
2021 edx_ecx,
2022 FeatureInfoFlags::PDCM
2023 );
2024
2025 check_flag!(
2026 doc = "Process-context identifiers. A value of 1 indicates that the processor \
2027 supports PCIDs and the software may set CR4.PCIDE to 1.",
2028 has_pcid,
2029 edx_ecx,
2030 FeatureInfoFlags::PCID
2031 );
2032
2033 check_flag!(
2034 doc = "A value of 1 indicates the processor supports the ability to prefetch \
2035 data from a memory mapped device.",
2036 has_dca,
2037 edx_ecx,
2038 FeatureInfoFlags::DCA
2039 );
2040
2041 check_flag!(
2042 doc = "A value of 1 indicates that the processor supports SSE4.1.",
2043 has_sse41,
2044 edx_ecx,
2045 FeatureInfoFlags::SSE41
2046 );
2047
2048 check_flag!(
2049 doc = "A value of 1 indicates that the processor supports SSE4.2.",
2050 has_sse42,
2051 edx_ecx,
2052 FeatureInfoFlags::SSE42
2053 );
2054
2055 check_flag!(
2056 doc = "A value of 1 indicates that the processor supports x2APIC feature.",
2057 has_x2apic,
2058 edx_ecx,
2059 FeatureInfoFlags::X2APIC
2060 );
2061
2062 check_flag!(
2063 doc = "A value of 1 indicates that the processor supports MOVBE instruction.",
2064 has_movbe,
2065 edx_ecx,
2066 FeatureInfoFlags::MOVBE
2067 );
2068
2069 check_flag!(
2070 doc = "A value of 1 indicates that the processor supports the POPCNT instruction.",
2071 has_popcnt,
2072 edx_ecx,
2073 FeatureInfoFlags::POPCNT
2074 );
2075
2076 check_flag!(
2077 doc = "A value of 1 indicates that the processors local APIC timer supports \
2078 one-shot operation using a TSC deadline value.",
2079 has_tsc_deadline,
2080 edx_ecx,
2081 FeatureInfoFlags::TSC_DEADLINE
2082 );
2083
2084 check_flag!(
2085 doc = "A value of 1 indicates that the processor supports the AESNI instruction \
2086 extensions.",
2087 has_aesni,
2088 edx_ecx,
2089 FeatureInfoFlags::AESNI
2090 );
2091
2092 check_flag!(
2093 doc = "A value of 1 indicates that the processor supports the XSAVE/XRSTOR \
2094 processor extended states feature, the XSETBV/XGETBV instructions, and \
2095 XCR0.",
2096 has_xsave,
2097 edx_ecx,
2098 FeatureInfoFlags::XSAVE
2099 );
2100
2101 check_flag!(
2102 doc = "A value of 1 indicates that the OS has enabled XSETBV/XGETBV instructions \
2103 to access XCR0, and support for processor extended state management using \
2104 XSAVE/XRSTOR.",
2105 has_oxsave,
2106 edx_ecx,
2107 FeatureInfoFlags::OSXSAVE
2108 );
2109
2110 check_flag!(
2111 doc = "A value of 1 indicates the processor supports the AVX instruction \
2112 extensions.",
2113 has_avx,
2114 edx_ecx,
2115 FeatureInfoFlags::AVX
2116 );
2117
2118 check_flag!(
2119 doc = "A value of 1 indicates that processor supports 16-bit floating-point \
2120 conversion instructions.",
2121 has_f16c,
2122 edx_ecx,
2123 FeatureInfoFlags::F16C
2124 );
2125
2126 check_flag!(
2127 doc = "A value of 1 indicates that processor supports RDRAND instruction.",
2128 has_rdrand,
2129 edx_ecx,
2130 FeatureInfoFlags::RDRAND
2131 );
2132
2133 check_flag!(
2134 doc = "A value of 1 indicates the indicates the presence of a hypervisor.",
2135 has_hypervisor,
2136 edx_ecx,
2137 FeatureInfoFlags::HYPERVISOR
2138 );
2139
2140 check_flag!(
2141 doc = "Floating Point Unit On-Chip. The processor contains an x87 FPU.",
2142 has_fpu,
2143 edx_ecx,
2144 FeatureInfoFlags::FPU
2145 );
2146
2147 check_flag!(
2148 doc = "Virtual 8086 Mode Enhancements. Virtual 8086 mode enhancements, including \
2149 CR4.VME for controlling the feature, CR4.PVI for protected mode virtual \
2150 interrupts, software interrupt indirection, expansion of the TSS with the \
2151 software indirection bitmap, and EFLAGS.VIF and EFLAGS.VIP flags.",
2152 has_vme,
2153 edx_ecx,
2154 FeatureInfoFlags::VME
2155 );
2156
2157 check_flag!(
2158 doc = "Debugging Extensions. Support for I/O breakpoints, including CR4.DE for \
2159 controlling the feature, and optional trapping of accesses to DR4 and DR5.",
2160 has_de,
2161 edx_ecx,
2162 FeatureInfoFlags::DE
2163 );
2164
2165 check_flag!(
2166 doc = "Page Size Extension. Large pages of size 4 MByte are supported, including \
2167 CR4.PSE for controlling the feature, the defined dirty bit in PDE (Page \
2168 Directory Entries), optional reserved bit trapping in CR3, PDEs, and PTEs.",
2169 has_pse,
2170 edx_ecx,
2171 FeatureInfoFlags::PSE
2172 );
2173
2174 check_flag!(
2175 doc = "Time Stamp Counter. The RDTSC instruction is supported, including CR4.TSD \
2176 for controlling privilege.",
2177 has_tsc,
2178 edx_ecx,
2179 FeatureInfoFlags::TSC
2180 );
2181
2182 check_flag!(
2183 doc = "Model Specific Registers RDMSR and WRMSR Instructions. The RDMSR and \
2184 WRMSR instructions are supported. Some of the MSRs are implementation \
2185 dependent.",
2186 has_msr,
2187 edx_ecx,
2188 FeatureInfoFlags::MSR
2189 );
2190
2191 check_flag!(
2192 doc = "Physical Address Extension. Physical addresses greater than 32 bits are \
2193 supported: extended page table entry formats, an extra level in the page \
2194 translation tables is defined, 2-MByte pages are supported instead of 4 \
2195 Mbyte pages if PAE bit is 1.",
2196 has_pae,
2197 edx_ecx,
2198 FeatureInfoFlags::PAE
2199 );
2200
2201 check_flag!(
2202 doc = "Machine Check Exception. Exception 18 is defined for Machine Checks, \
2203 including CR4.MCE for controlling the feature. This feature does not \
2204 define the model-specific implementations of machine-check error logging, \
2205 reporting, and processor shutdowns. Machine Check exception handlers may \
2206 have to depend on processor version to do model specific processing of \
2207 the exception, or test for the presence of the Machine Check feature.",
2208 has_mce,
2209 edx_ecx,
2210 FeatureInfoFlags::MCE
2211 );
2212
2213 check_flag!(
2214 doc = "CMPXCHG8B Instruction. The compare-and-exchange 8 bytes (64 bits) \
2215 instruction is supported (implicitly locked and atomic).",
2216 has_cmpxchg8b,
2217 edx_ecx,
2218 FeatureInfoFlags::CX8
2219 );
2220
2221 check_flag!(
2222 doc = "APIC On-Chip. The processor contains an Advanced Programmable Interrupt \
2223 Controller (APIC), responding to memory mapped commands in the physical \
2224 address range FFFE0000H to FFFE0FFFH (by default - some processors permit \
2225 the APIC to be relocated).",
2226 has_apic,
2227 edx_ecx,
2228 FeatureInfoFlags::APIC
2229 );
2230
2231 check_flag!(
2232 doc = "SYSENTER and SYSEXIT Instructions. The SYSENTER and SYSEXIT and \
2233 associated MSRs are supported.",
2234 has_sysenter_sysexit,
2235 edx_ecx,
2236 FeatureInfoFlags::SEP
2237 );
2238
2239 check_flag!(
2240 doc = "Memory Type Range Registers. MTRRs are supported. The MTRRcap MSR \
2241 contains feature bits that describe what memory types are supported, how \
2242 many variable MTRRs are supported, and whether fixed MTRRs are supported.",
2243 has_mtrr,
2244 edx_ecx,
2245 FeatureInfoFlags::MTRR
2246 );
2247
2248 check_flag!(
2249 doc = "Page Global Bit. The global bit is supported in paging-structure entries \
2250 that map a page, indicating TLB entries that are common to different \
2251 processes and need not be flushed. The CR4.PGE bit controls this feature.",
2252 has_pge,
2253 edx_ecx,
2254 FeatureInfoFlags::PGE
2255 );
2256
2257 check_flag!(
2258 doc = "Machine Check Architecture. A value of 1 indicates the Machine Check \
2259 Architecture of reporting machine errors is supported. The MCG_CAP MSR \
2260 contains feature bits describing how many banks of error reporting MSRs \
2261 are supported.",
2262 has_mca,
2263 edx_ecx,
2264 FeatureInfoFlags::MCA
2265 );
2266
2267 check_flag!(
2268 doc = "Conditional Move Instructions. The conditional move instruction CMOV is \
2269 supported. In addition, if x87 FPU is present as indicated by the \
2270 CPUID.FPU feature bit, then the FCOMI and FCMOV instructions are supported",
2271 has_cmov,
2272 edx_ecx,
2273 FeatureInfoFlags::CMOV
2274 );
2275
2276 check_flag!(
2277 doc = "Page Attribute Table. Page Attribute Table is supported. This feature \
2278 augments the Memory Type Range Registers (MTRRs), allowing an operating \
2279 system to specify attributes of memory accessed through a linear address \
2280 on a 4KB granularity.",
2281 has_pat,
2282 edx_ecx,
2283 FeatureInfoFlags::PAT
2284 );
2285
2286 check_flag!(
2287 doc = "36-Bit Page Size Extension. 4-MByte pages addressing physical memory \
2288 beyond 4 GBytes are supported with 32-bit paging. This feature indicates \
2289 that upper bits of the physical address of a 4-MByte page are encoded in \
2290 bits 20:13 of the page-directory entry. Such physical addresses are \
2291 limited by MAXPHYADDR and may be up to 40 bits in size.",
2292 has_pse36,
2293 edx_ecx,
2294 FeatureInfoFlags::PSE36
2295 );
2296
2297 check_flag!(
2298 doc = "Processor Serial Number. The processor supports the 96-bit processor \
2299 identification number feature and the feature is enabled.",
2300 has_psn,
2301 edx_ecx,
2302 FeatureInfoFlags::PSN
2303 );
2304
2305 check_flag!(
2306 doc = "CLFLUSH Instruction. CLFLUSH Instruction is supported.",
2307 has_clflush,
2308 edx_ecx,
2309 FeatureInfoFlags::CLFSH
2310 );
2311
2312 check_flag!(
2313 doc = "Debug Store. The processor supports the ability to write debug \
2314 information into a memory resident buffer. This feature is used by the \
2315 branch trace store (BTS) and processor event-based sampling (PEBS) \
2316 facilities (see Chapter 23, Introduction to Virtual-Machine Extensions, \
2317 in the Intel® 64 and IA-32 Architectures Software Developers Manual, \
2318 Volume 3C).",
2319 has_ds,
2320 edx_ecx,
2321 FeatureInfoFlags::DS
2322 );
2323
2324 check_flag!(
2325 doc = "Thermal Monitor and Software Controlled Clock Facilities. The processor \
2326 implements internal MSRs that allow processor temperature to be monitored \
2327 and processor performance to be modulated in predefined duty cycles under \
2328 software control.",
2329 has_acpi,
2330 edx_ecx,
2331 FeatureInfoFlags::ACPI
2332 );
2333
2334 check_flag!(
2335 doc = "Intel MMX Technology. The processor supports the Intel MMX technology.",
2336 has_mmx,
2337 edx_ecx,
2338 FeatureInfoFlags::MMX
2339 );
2340
2341 check_flag!(
2342 doc = "FXSAVE and FXRSTOR Instructions. The FXSAVE and FXRSTOR instructions are \
2343 supported for fast save and restore of the floating point context. \
2344 Presence of this bit also indicates that CR4.OSFXSR is available for an \
2345 operating system to indicate that it supports the FXSAVE and FXRSTOR \
2346 instructions.",
2347 has_fxsave_fxstor,
2348 edx_ecx,
2349 FeatureInfoFlags::FXSR
2350 );
2351
2352 check_flag!(
2353 doc = "SSE. The processor supports the SSE extensions.",
2354 has_sse,
2355 edx_ecx,
2356 FeatureInfoFlags::SSE
2357 );
2358
2359 check_flag!(
2360 doc = "SSE2. The processor supports the SSE2 extensions.",
2361 has_sse2,
2362 edx_ecx,
2363 FeatureInfoFlags::SSE2
2364 );
2365
2366 check_flag!(
2367 doc = "Self Snoop. The processor supports the management of conflicting memory \
2368 types by performing a snoop of its own cache structure for transactions \
2369 issued to the bus.",
2370 has_ss,
2371 edx_ecx,
2372 FeatureInfoFlags::SS
2373 );
2374
2375 check_flag!(
2376 doc = "Max APIC IDs reserved field is Valid. A value of 0 for HTT indicates \
2377 there is only a single logical processor in the package and software \
2378 should assume only a single APIC ID is reserved. A value of 1 for HTT \
2379 indicates the value in CPUID.1.EBX\\[23:16\\] (the Maximum number of \
2380 addressable IDs for logical processors in this package) is valid for the \
2381 package.",
2382 has_htt,
2383 edx_ecx,
2384 FeatureInfoFlags::HTT
2385 );
2386
2387 check_flag!(
2388 doc = "Thermal Monitor. The processor implements the thermal monitor automatic \
2389 thermal control circuitry (TCC).",
2390 has_tm,
2391 edx_ecx,
2392 FeatureInfoFlags::TM
2393 );
2394
2395 check_flag!(
2396 doc = "Pending Break Enable. The processor supports the use of the FERR#/PBE# \
2397 pin when the processor is in the stop-clock state (STPCLK# is asserted) \
2398 to signal the processor that an interrupt is pending and that the \
2399 processor should return to normal operation to handle the interrupt. Bit \
2400 10 (PBE enable) in the IA32_MISC_ENABLE MSR enables this capability.",
2401 has_pbe,
2402 edx_ecx,
2403 FeatureInfoFlags::PBE
2404 );
2405}
2406
2407impl Debug for FeatureInfo {
2408 fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
2409 f.debug_struct("FeatureInfo")
2410 .field("extended_family_id", &self.extended_family_id())
2411 .field("extended_model_id", &self.extended_model_id())
2412 .field("family_id", &self.family_id())
2413 .field("model_id", &self.model_id())
2414 .field("stepping_id", &self.stepping_id())
2415 .field("brand_index", &self.brand_index())
2416 .field("cflush_cache_line_size", &self.cflush_cache_line_size())
2417 .field("initial_local_apic_id", &self.initial_local_apic_id())
2418 .field(
2419 "max_logical_processor_ids",
2420 &self.max_logical_processor_ids(),
2421 )
2422 .field("edx_ecx", &self.edx_ecx)
2423 .finish()
2424 }
2425}
2426
2427bitflags! {
2428 #[repr(transparent)]
2429 #[derive(Debug, Clone, Copy, PartialEq, Eq)]
2430 struct FeatureInfoFlags: u64 {
2431 const SSE3 = 1 << 0;
2435 const PCLMULQDQ = 1 << 1;
2437 const DTES64 = 1 << 2;
2439 const MONITOR = 1 << 3;
2441 const DSCPL = 1 << 4;
2443 const VMX = 1 << 5;
2445 const SMX = 1 << 6;
2447 const EIST = 1 << 7;
2449 const TM2 = 1 << 8;
2451 const SSSE3 = 1 << 9;
2453 const CNXTID = 1 << 10;
2455 const FMA = 1 << 12;
2457 const CMPXCHG16B = 1 << 13;
2459 const PDCM = 1 << 15;
2461 const PCID = 1 << 17;
2463 const DCA = 1 << 18;
2465 const SSE41 = 1 << 19;
2467 const SSE42 = 1 << 20;
2469 const X2APIC = 1 << 21;
2471 const MOVBE = 1 << 22;
2473 const POPCNT = 1 << 23;
2475 const TSC_DEADLINE = 1 << 24;
2477 const AESNI = 1 << 25;
2479 const XSAVE = 1 << 26;
2481 const OSXSAVE = 1 << 27;
2483 const AVX = 1 << 28;
2485 const F16C = 1 << 29;
2487 const RDRAND = 1 << 30;
2489 const HYPERVISOR = 1 << 31;
2491
2492
2493 const FPU = 1 << 32;
2497 const VME = 1 << (32 + 1);
2499 const DE = 1 << (32 + 2);
2501 const PSE = 1 << (32 + 3);
2503 const TSC = 1 << (32 + 4);
2505 const MSR = 1 << (32 + 5);
2507 const PAE = 1 << (32 + 6);
2509 const MCE = 1 << (32 + 7);
2511 const CX8 = 1 << (32 + 8);
2513 const APIC = 1 << (32 + 9);
2515 const SEP = 1 << (32 + 11);
2517 const MTRR = 1 << (32 + 12);
2519 const PGE = 1 << (32 + 13);
2521 const MCA = 1 << (32 + 14);
2523 const CMOV = 1 << (32 + 15);
2525 const PAT = 1 << (32 + 16);
2527 const PSE36 = 1 << (32 + 17);
2529 const PSN = 1 << (32 + 18);
2531 const CLFSH = 1 << (32 + 19);
2533 const DS = 1 << (32 + 21);
2535 const ACPI = 1 << (32 + 22);
2537 const MMX = 1 << (32 + 23);
2539 const FXSR = 1 << (32 + 24);
2541 const SSE = 1 << (32 + 25);
2543 const SSE2 = 1 << (32 + 26);
2545 const SS = 1 << (32 + 27);
2547 const HTT = 1 << (32 + 28);
2549 const TM = 1 << (32 + 29);
2551 const PBE = 1 << (32 + 31);
2553 }
2554}
2555
2556#[derive(Clone, Copy)]
2563pub struct CacheParametersIter<R: CpuIdReader> {
2564 read: R,
2565 leaf: u32,
2566 current: u32,
2567}
2568
2569impl<R: CpuIdReader> Iterator for CacheParametersIter<R> {
2570 type Item = CacheParameter;
2571
2572 fn next(&mut self) -> Option<CacheParameter> {
2578 let res = self.read.cpuid2(self.leaf, self.current);
2579 let cp = CacheParameter {
2580 eax: res.eax,
2581 ebx: res.ebx,
2582 ecx: res.ecx,
2583 edx: res.edx,
2584 };
2585
2586 match cp.cache_type() {
2587 CacheType::Null => None,
2588 CacheType::Reserved => None,
2589 _ => {
2590 self.current += 1;
2591 Some(cp)
2592 }
2593 }
2594 }
2595}
2596
2597impl<R: CpuIdReader> Debug for CacheParametersIter<R> {
2598 fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
2599 let mut debug = f.debug_list();
2600 self.clone().for_each(|ref item| {
2601 debug.entry(item);
2602 });
2603 debug.finish()
2604 }
2605}
2606
2607#[derive(Copy, Clone, Eq, PartialEq)]
2612pub struct CacheParameter {
2613 eax: u32,
2614 ebx: u32,
2615 ecx: u32,
2616 edx: u32,
2617}
2618
2619#[derive(PartialEq, Eq, Debug)]
2621pub enum CacheType {
2622 Null = 0,
2624 Data,
2626 Instruction,
2628 Unified,
2630 Reserved,
2632}
2633
2634impl fmt::Display for CacheType {
2635 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2636 let typ = match self {
2637 CacheType::Null => "Null",
2638 CacheType::Data => "Data",
2639 CacheType::Instruction => "Instruction",
2640 CacheType::Unified => "Unified",
2641 CacheType::Reserved => "Reserved",
2642 };
2643
2644 f.write_str(typ)
2645 }
2646}
2647
2648impl CacheParameter {
2649 pub fn cache_type(&self) -> CacheType {
2654 let typ = get_bits(self.eax, 0, 4) as u8;
2655 match typ {
2656 0 => CacheType::Null,
2657 1 => CacheType::Data,
2658 2 => CacheType::Instruction,
2659 3 => CacheType::Unified,
2660 _ => CacheType::Reserved,
2661 }
2662 }
2663
2664 pub fn level(&self) -> u8 {
2669 get_bits(self.eax, 5, 7) as u8
2670 }
2671
2672 pub fn is_self_initializing(&self) -> bool {
2677 get_bits(self.eax, 8, 8) == 1
2678 }
2679
2680 pub fn is_fully_associative(&self) -> bool {
2685 get_bits(self.eax, 9, 9) == 1
2686 }
2687
2688 pub fn max_cores_for_cache(&self) -> usize {
2693 (get_bits(self.eax, 14, 25) + 1) as usize
2694 }
2695
2696 pub fn max_cores_for_package(&self) -> usize {
2701 (get_bits(self.eax, 26, 31) + 1) as usize
2702 }
2703
2704 pub fn coherency_line_size(&self) -> usize {
2709 (get_bits(self.ebx, 0, 11) + 1) as usize
2710 }
2711
2712 pub fn physical_line_partitions(&self) -> usize {
2717 (get_bits(self.ebx, 12, 21) + 1) as usize
2718 }
2719
2720 pub fn associativity(&self) -> usize {
2725 (get_bits(self.ebx, 22, 31) + 1) as usize
2726 }
2727
2728 pub fn sets(&self) -> usize {
2733 (self.ecx + 1) as usize
2734 }
2735
2736 pub fn is_write_back_invalidate(&self) -> bool {
2743 get_bits(self.edx, 0, 0) == 1
2744 }
2745
2746 pub fn is_inclusive(&self) -> bool {
2753 get_bits(self.edx, 1, 1) == 1
2754 }
2755
2756 pub fn has_complex_indexing(&self) -> bool {
2763 get_bits(self.edx, 2, 2) == 1
2764 }
2765}
2766
2767impl Debug for CacheParameter {
2768 fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
2769 f.debug_struct("CacheParameter")
2770 .field("cache_type", &self.cache_type())
2771 .field("level", &self.level())
2772 .field("is_self_initializing", &self.is_self_initializing())
2773 .field("is_fully_associative", &self.is_fully_associative())
2774 .field("max_cores_for_cache", &self.max_cores_for_cache())
2775 .field("max_cores_for_package", &self.max_cores_for_package())
2776 .field("coherency_line_size", &self.coherency_line_size())
2777 .field("physical_line_partitions", &self.physical_line_partitions())
2778 .field("associativity", &self.associativity())
2779 .field("sets", &self.sets())
2780 .field("is_write_back_invalidate", &self.is_write_back_invalidate())
2781 .field("is_inclusive", &self.is_inclusive())
2782 .field("has_complex_indexing", &self.has_complex_indexing())
2783 .finish()
2784 }
2785}
2786
2787#[derive(Eq, PartialEq)]
2792pub struct MonitorMwaitInfo {
2793 eax: u32,
2794 ebx: u32,
2795 ecx: u32,
2796 edx: u32,
2797}
2798
2799impl MonitorMwaitInfo {
2800 pub fn smallest_monitor_line(&self) -> u16 {
2805 get_bits(self.eax, 0, 15) as u16
2806 }
2807
2808 pub fn largest_monitor_line(&self) -> u16 {
2813 get_bits(self.ebx, 0, 15) as u16
2814 }
2815
2816 pub fn extensions_supported(&self) -> bool {
2821 get_bits(self.ecx, 0, 0) == 1
2822 }
2823
2824 pub fn interrupts_as_break_event(&self) -> bool {
2829 get_bits(self.ecx, 1, 1) == 1
2830 }
2831
2832 pub fn supported_c0_states(&self) -> u16 {
2837 get_bits(self.edx, 0, 3) as u16
2838 }
2839
2840 pub fn supported_c1_states(&self) -> u16 {
2845 get_bits(self.edx, 4, 7) as u16
2846 }
2847
2848 pub fn supported_c2_states(&self) -> u16 {
2853 get_bits(self.edx, 8, 11) as u16
2854 }
2855
2856 pub fn supported_c3_states(&self) -> u16 {
2861 get_bits(self.edx, 12, 15) as u16
2862 }
2863
2864 pub fn supported_c4_states(&self) -> u16 {
2869 get_bits(self.edx, 16, 19) as u16
2870 }
2871
2872 pub fn supported_c5_states(&self) -> u16 {
2877 get_bits(self.edx, 20, 23) as u16
2878 }
2879
2880 pub fn supported_c6_states(&self) -> u16 {
2885 get_bits(self.edx, 24, 27) as u16
2886 }
2887
2888 pub fn supported_c7_states(&self) -> u16 {
2893 get_bits(self.edx, 28, 31) as u16
2894 }
2895}
2896
2897impl Debug for MonitorMwaitInfo {
2898 fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
2899 f.debug_struct("MonitorMwaitInfo")
2900 .field("smallest_monitor_line", &self.smallest_monitor_line())
2901 .field("largest_monitor_line", &self.largest_monitor_line())
2902 .field("extensions_supported", &self.extensions_supported())
2903 .field(
2904 "interrupts_as_break_event",
2905 &self.interrupts_as_break_event(),
2906 )
2907 .field("supported_c0_states", &self.supported_c0_states())
2908 .field("supported_c1_states", &self.supported_c1_states())
2909 .field("supported_c2_states", &self.supported_c2_states())
2910 .field("supported_c3_states", &self.supported_c3_states())
2911 .field("supported_c4_states", &self.supported_c4_states())
2912 .field("supported_c5_states", &self.supported_c5_states())
2913 .field("supported_c6_states", &self.supported_c6_states())
2914 .field("supported_c7_states", &self.supported_c7_states())
2915 .finish()
2916 }
2917}
2918
2919pub struct ThermalPowerInfo {
2924 eax: ThermalPowerFeaturesEax,
2925 ebx: u32,
2926 ecx: ThermalPowerFeaturesEcx,
2927 _edx: u32,
2928}
2929
2930impl ThermalPowerInfo {
2931 pub fn dts_irq_threshold(&self) -> u8 {
2936 get_bits(self.ebx, 0, 3) as u8
2937 }
2938
2939 pub fn has_dts(&self) -> bool {
2944 self.eax.contains(ThermalPowerFeaturesEax::DTS)
2945 }
2946
2947 pub fn has_turbo_boost(&self) -> bool {
2953 self.eax.contains(ThermalPowerFeaturesEax::TURBO_BOOST)
2954 }
2955
2956 pub fn has_arat(&self) -> bool {
2961 self.eax.contains(ThermalPowerFeaturesEax::ARAT)
2962 }
2963
2964 pub fn has_pln(&self) -> bool {
2969 self.eax.contains(ThermalPowerFeaturesEax::PLN)
2970 }
2971
2972 pub fn has_ecmd(&self) -> bool {
2977 self.eax.contains(ThermalPowerFeaturesEax::ECMD)
2978 }
2979
2980 pub fn has_ptm(&self) -> bool {
2985 self.eax.contains(ThermalPowerFeaturesEax::PTM)
2986 }
2987
2988 pub fn has_hwp(&self) -> bool {
2994 self.eax.contains(ThermalPowerFeaturesEax::HWP)
2995 }
2996
2997 pub fn has_hwp_notification(&self) -> bool {
3002 self.eax.contains(ThermalPowerFeaturesEax::HWP_NOTIFICATION)
3003 }
3004
3005 pub fn has_hwp_activity_window(&self) -> bool {
3010 self.eax
3011 .contains(ThermalPowerFeaturesEax::HWP_ACTIVITY_WINDOW)
3012 }
3013
3014 pub fn has_hwp_energy_performance_preference(&self) -> bool {
3020 self.eax
3021 .contains(ThermalPowerFeaturesEax::HWP_ENERGY_PERFORMANCE_PREFERENCE)
3022 }
3023
3024 pub fn has_hwp_package_level_request(&self) -> bool {
3029 self.eax
3030 .contains(ThermalPowerFeaturesEax::HWP_PACKAGE_LEVEL_REQUEST)
3031 }
3032
3033 pub fn has_hdc(&self) -> bool {
3039 self.eax.contains(ThermalPowerFeaturesEax::HDC)
3040 }
3041
3042 pub fn has_turbo_boost3(&self) -> bool {
3047 self.eax.contains(ThermalPowerFeaturesEax::TURBO_BOOST_3)
3048 }
3049
3050 pub fn has_hwp_capabilities(&self) -> bool {
3055 self.eax.contains(ThermalPowerFeaturesEax::HWP_CAPABILITIES)
3056 }
3057
3058 pub fn has_hwp_peci_override(&self) -> bool {
3063 self.eax
3064 .contains(ThermalPowerFeaturesEax::HWP_PECI_OVERRIDE)
3065 }
3066
3067 pub fn has_flexible_hwp(&self) -> bool {
3072 self.eax.contains(ThermalPowerFeaturesEax::FLEXIBLE_HWP)
3073 }
3074
3075 pub fn has_hwp_fast_access_mode(&self) -> bool {
3080 self.eax
3081 .contains(ThermalPowerFeaturesEax::HWP_REQUEST_MSR_FAST_ACCESS)
3082 }
3083
3084 pub fn has_ignore_idle_processor_hwp_request(&self) -> bool {
3089 self.eax
3090 .contains(ThermalPowerFeaturesEax::IGNORE_IDLE_PROCESSOR_HWP_REQUEST)
3091 }
3092
3093 pub fn has_hw_coord_feedback(&self) -> bool {
3105 self.ecx
3106 .contains(ThermalPowerFeaturesEcx::HW_COORD_FEEDBACK)
3107 }
3108
3109 pub fn has_energy_bias_pref(&self) -> bool {
3116 self.ecx.contains(ThermalPowerFeaturesEcx::ENERGY_BIAS_PREF)
3117 }
3118}
3119
3120impl Debug for ThermalPowerInfo {
3121 fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
3122 f.debug_struct("ThermalPowerInfo")
3123 .field("dts_irq_threshold", &self.dts_irq_threshold())
3124 .field("has_dts", &self.has_dts())
3125 .field("has_arat", &self.has_arat())
3126 .field("has_pln", &self.has_pln())
3127 .field("has_ecmd", &self.has_ecmd())
3128 .field("has_ptm", &self.has_ptm())
3129 .field("has_hwp", &self.has_hwp())
3130 .field("has_hwp_notification", &self.has_hwp_notification())
3131 .field("has_hwp_activity_window", &self.has_hwp_activity_window())
3132 .field(
3133 "has_hwp_energy_performance_preference",
3134 &self.has_hwp_energy_performance_preference(),
3135 )
3136 .field(
3137 "has_hwp_package_level_request",
3138 &self.has_hwp_package_level_request(),
3139 )
3140 .field("has_hdc", &self.has_hdc())
3141 .field("has_turbo_boost3", &self.has_turbo_boost3())
3142 .field("has_hwp_capabilities", &self.has_hwp_capabilities())
3143 .field("has_hwp_peci_override", &self.has_hwp_peci_override())
3144 .field("has_flexible_hwp", &self.has_flexible_hwp())
3145 .field("has_hwp_fast_access_mode", &self.has_hwp_fast_access_mode())
3146 .field(
3147 "has_ignore_idle_processor_hwp_request",
3148 &self.has_ignore_idle_processor_hwp_request(),
3149 )
3150 .field("has_hw_coord_feedback", &self.has_hw_coord_feedback())
3151 .field("has_energy_bias_pref", &self.has_energy_bias_pref())
3152 .finish()
3153 }
3154}
3155
3156bitflags! {
3157 struct ThermalPowerFeaturesEax: u32 {
3158 const DTS = 1 << 0;
3160 const TURBO_BOOST = 1 << 1;
3162 const ARAT = 1 << 2;
3164 const RESERVED_3 = 1 << 3;
3166 const PLN = 1 << 4;
3168 const ECMD = 1 << 5;
3170 const PTM = 1 << 6;
3172 const HWP = 1 << 7;
3174 const HWP_NOTIFICATION = 1 << 8;
3176 const HWP_ACTIVITY_WINDOW = 1 << 9;
3178 const HWP_ENERGY_PERFORMANCE_PREFERENCE = 1 << 10;
3180 const HWP_PACKAGE_LEVEL_REQUEST = 1 << 11;
3182 const RESERVED_12 = 1 << 12;
3184 const HDC = 1 << 13;
3186 const TURBO_BOOST_3 = 1 << 14;
3188 const HWP_CAPABILITIES = 1 << 15;
3190 const HWP_PECI_OVERRIDE = 1 << 16;
3192 const FLEXIBLE_HWP = 1 << 17;
3194 const HWP_REQUEST_MSR_FAST_ACCESS = 1 << 18;
3196 const RESERVED_19 = 1 << 19;
3198 const IGNORE_IDLE_PROCESSOR_HWP_REQUEST = 1 << 20;
3200 }
3202}
3203
3204bitflags! {
3205 struct ThermalPowerFeaturesEcx: u32 {
3206 const HW_COORD_FEEDBACK = 1 << 0;
3207
3208 const ENERGY_BIAS_PREF = 1 << 3;
3210 }
3211}
3212
3213pub struct ExtendedFeatures {
3218 _eax: u32,
3219 ebx: ExtendedFeaturesEbx,
3220 ecx: ExtendedFeaturesEcx,
3221 edx: ExtendedFeaturesEdx,
3222}
3223
3224impl ExtendedFeatures {
3225 #[inline]
3230 pub const fn has_fsgsbase(&self) -> bool {
3231 self.ebx.contains(ExtendedFeaturesEbx::FSGSBASE)
3232 }
3233
3234 #[inline]
3239 pub const fn has_tsc_adjust_msr(&self) -> bool {
3240 self.ebx.contains(ExtendedFeaturesEbx::ADJUST_MSR)
3241 }
3242
3243 #[inline]
3248 pub const fn has_bmi1(&self) -> bool {
3249 self.ebx.contains(ExtendedFeaturesEbx::BMI1)
3250 }
3251
3252 #[inline]
3257 pub const fn has_hle(&self) -> bool {
3258 self.ebx.contains(ExtendedFeaturesEbx::HLE)
3259 }
3260
3261 #[inline]
3266 pub const fn has_avx2(&self) -> bool {
3267 self.ebx.contains(ExtendedFeaturesEbx::AVX2)
3268 }
3269
3270 #[inline]
3276 pub const fn has_fdp(&self) -> bool {
3277 self.ebx.contains(ExtendedFeaturesEbx::FDP)
3278 }
3279
3280 #[inline]
3285 pub const fn has_smep(&self) -> bool {
3286 self.ebx.contains(ExtendedFeaturesEbx::SMEP)
3287 }
3288
3289 #[inline]
3294 pub const fn has_bmi2(&self) -> bool {
3295 self.ebx.contains(ExtendedFeaturesEbx::BMI2)
3296 }
3297
3298 #[inline]
3303 pub const fn has_rep_movsb_stosb(&self) -> bool {
3304 self.ebx.contains(ExtendedFeaturesEbx::REP_MOVSB_STOSB)
3305 }
3306
3307 #[inline]
3313 pub const fn has_invpcid(&self) -> bool {
3314 self.ebx.contains(ExtendedFeaturesEbx::INVPCID)
3315 }
3316
3317 #[inline]
3322 pub const fn has_rtm(&self) -> bool {
3323 self.ebx.contains(ExtendedFeaturesEbx::RTM)
3324 }
3325
3326 #[inline]
3331 pub const fn has_rdtm(&self) -> bool {
3332 self.ebx.contains(ExtendedFeaturesEbx::RDTM)
3333 }
3334
3335 #[inline]
3340 pub const fn has_fpu_cs_ds_deprecated(&self) -> bool {
3341 self.ebx.contains(ExtendedFeaturesEbx::DEPRECATE_FPU_CS_DS)
3342 }
3343
3344 #[inline]
3349 pub const fn has_mpx(&self) -> bool {
3350 self.ebx.contains(ExtendedFeaturesEbx::MPX)
3351 }
3352
3353 #[inline]
3358 pub const fn has_rdta(&self) -> bool {
3359 self.ebx.contains(ExtendedFeaturesEbx::RDTA)
3360 }
3361
3362 #[inline]
3367 pub const fn has_rdseed(&self) -> bool {
3368 self.ebx.contains(ExtendedFeaturesEbx::RDSEED)
3369 }
3370
3371 #[inline]
3376 pub const fn has_adx(&self) -> bool {
3377 self.ebx.contains(ExtendedFeaturesEbx::ADX)
3378 }
3379
3380 #[inline]
3386 pub const fn has_smap(&self) -> bool {
3387 self.ebx.contains(ExtendedFeaturesEbx::SMAP)
3388 }
3389
3390 #[inline]
3395 pub const fn has_clflushopt(&self) -> bool {
3396 self.ebx.contains(ExtendedFeaturesEbx::CLFLUSHOPT)
3397 }
3398
3399 #[inline]
3404 pub const fn has_processor_trace(&self) -> bool {
3405 self.ebx.contains(ExtendedFeaturesEbx::PROCESSOR_TRACE)
3406 }
3407
3408 #[inline]
3413 pub const fn has_sha(&self) -> bool {
3414 self.ebx.contains(ExtendedFeaturesEbx::SHA)
3415 }
3416
3417 #[inline]
3422 pub const fn has_sgx(&self) -> bool {
3423 self.ebx.contains(ExtendedFeaturesEbx::SGX)
3424 }
3425
3426 #[inline]
3431 pub const fn has_avx512f(&self) -> bool {
3432 self.ebx.contains(ExtendedFeaturesEbx::AVX512F)
3433 }
3434
3435 #[inline]
3440 pub const fn has_avx512dq(&self) -> bool {
3441 self.ebx.contains(ExtendedFeaturesEbx::AVX512DQ)
3442 }
3443
3444 #[inline]
3449 pub const fn has_avx512_ifma(&self) -> bool {
3450 self.ebx.contains(ExtendedFeaturesEbx::AVX512_IFMA)
3451 }
3452
3453 #[inline]
3458 pub const fn has_avx512pf(&self) -> bool {
3459 self.ebx.contains(ExtendedFeaturesEbx::AVX512PF)
3460 }
3461
3462 #[inline]
3467 pub const fn has_avx512er(&self) -> bool {
3468 self.ebx.contains(ExtendedFeaturesEbx::AVX512ER)
3469 }
3470
3471 #[inline]
3476 pub const fn has_avx512cd(&self) -> bool {
3477 self.ebx.contains(ExtendedFeaturesEbx::AVX512CD)
3478 }
3479
3480 #[inline]
3485 pub const fn has_avx512bw(&self) -> bool {
3486 self.ebx.contains(ExtendedFeaturesEbx::AVX512BW)
3487 }
3488
3489 #[inline]
3494 pub const fn has_avx512vl(&self) -> bool {
3495 self.ebx.contains(ExtendedFeaturesEbx::AVX512VL)
3496 }
3497
3498 #[inline]
3503 pub const fn has_clwb(&self) -> bool {
3504 self.ebx.contains(ExtendedFeaturesEbx::CLWB)
3505 }
3506
3507 #[inline]
3512 pub const fn has_prefetchwt1(&self) -> bool {
3513 self.ecx.contains(ExtendedFeaturesEcx::PREFETCHWT1)
3514 }
3515
3516 #[inline]
3521 pub const fn has_umip(&self) -> bool {
3522 self.ecx.contains(ExtendedFeaturesEcx::UMIP)
3523 }
3524
3525 #[inline]
3530 pub const fn has_pku(&self) -> bool {
3531 self.ecx.contains(ExtendedFeaturesEcx::PKU)
3532 }
3533
3534 #[inline]
3540 pub const fn has_ospke(&self) -> bool {
3541 self.ecx.contains(ExtendedFeaturesEcx::OSPKE)
3542 }
3543
3544 #[inline]
3548 pub const fn has_waitpkg(&self) -> bool {
3549 self.ecx.contains(ExtendedFeaturesEcx::WAITPKG)
3550 }
3551
3552 #[inline]
3556 pub const fn has_av512vbmi2(&self) -> bool {
3557 self.ecx.contains(ExtendedFeaturesEcx::AVX512VBMI2)
3558 }
3559
3560 #[inline]
3566 pub const fn has_cet_ss(&self) -> bool {
3567 self.ecx.contains(ExtendedFeaturesEcx::GFNI)
3568 }
3569
3570 #[inline]
3574 pub const fn has_gfni(&self) -> bool {
3575 self.ecx.contains(ExtendedFeaturesEcx::GFNI)
3576 }
3577
3578 #[inline]
3582 pub const fn has_vaes(&self) -> bool {
3583 self.ecx.contains(ExtendedFeaturesEcx::VAES)
3584 }
3585
3586 #[inline]
3590 pub const fn has_vpclmulqdq(&self) -> bool {
3591 self.ecx.contains(ExtendedFeaturesEcx::VPCLMULQDQ)
3592 }
3593
3594 #[inline]
3599 pub const fn has_avx512vnni(&self) -> bool {
3600 self.ecx.contains(ExtendedFeaturesEcx::AVX512VNNI)
3601 }
3602
3603 #[inline]
3607 pub const fn has_avx512bitalg(&self) -> bool {
3608 self.ecx.contains(ExtendedFeaturesEcx::AVX512BITALG)
3609 }
3610
3611 #[inline]
3616 pub const fn has_tme_en(&self) -> bool {
3617 self.ecx.contains(ExtendedFeaturesEcx::TMEEN)
3618 }
3619
3620 #[inline]
3624 pub const fn has_avx512vpopcntdq(&self) -> bool {
3625 self.ecx.contains(ExtendedFeaturesEcx::AVX512VPOPCNTDQ)
3626 }
3627
3628 #[inline]
3633 pub const fn has_la57(&self) -> bool {
3634 self.ecx.contains(ExtendedFeaturesEcx::LA57)
3635 }
3636
3637 #[inline]
3647 pub const fn has_rdpid(&self) -> bool {
3648 self.ecx.contains(ExtendedFeaturesEcx::RDPID)
3649 }
3650
3651 #[inline]
3656 pub const fn has_sgx_lc(&self) -> bool {
3657 self.ecx.contains(ExtendedFeaturesEcx::SGX_LC)
3658 }
3659
3660 #[inline]
3665 pub fn mawau_value(&self) -> u8 {
3666 get_bits(self.ecx.bits(), 17, 21) as u8
3667 }
3668
3669 #[inline]
3674 pub const fn has_avx512_4vnniw(&self) -> bool {
3675 self.edx.contains(ExtendedFeaturesEdx::AVX512_4VNNIW)
3676 }
3677
3678 #[inline]
3683 pub const fn has_avx512_4fmaps(&self) -> bool {
3684 self.edx.contains(ExtendedFeaturesEdx::AVX512_4FMAPS)
3685 }
3686
3687 #[inline]
3692 pub const fn has_avx512_vp2intersect(&self) -> bool {
3693 self.edx.contains(ExtendedFeaturesEdx::AVX512_VP2INTERSECT)
3694 }
3695
3696 #[inline]
3701 pub const fn has_amx_bf16(&self) -> bool {
3702 self.edx.contains(ExtendedFeaturesEdx::AMX_BF16)
3703 }
3704
3705 #[inline]
3710 pub const fn has_avx512_fp16(&self) -> bool {
3711 self.edx.contains(ExtendedFeaturesEdx::AVX512_FP16)
3712 }
3713
3714 #[inline]
3719 pub const fn has_amx_tile(&self) -> bool {
3720 self.edx.contains(ExtendedFeaturesEdx::AMX_TILE)
3721 }
3722
3723 #[inline]
3728 pub const fn has_amx_int8(&self) -> bool {
3729 self.edx.contains(ExtendedFeaturesEdx::AMX_INT8)
3730 }
3731}
3732
3733impl Debug for ExtendedFeatures {
3734 fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
3735 f.debug_struct("ExtendedFeatures")
3736 .field("ebx", &self.ebx)
3737 .field("ecx", &self.ecx)
3738 .field("mawau_value", &self.mawau_value())
3739 .finish()
3740 }
3741}
3742
3743bitflags! {
3744 #[repr(transparent)]
3745 #[derive(Debug, Clone, Copy, PartialEq, Eq)]
3746 struct ExtendedFeaturesEbx: u32 {
3747 const FSGSBASE = 1 << 0;
3749 const ADJUST_MSR = 1 << 1;
3751 const SGX = 1 << 2;
3753 const BMI1 = 1 << 3;
3755 const HLE = 1 << 4;
3757 const AVX2 = 1 << 5;
3759 const FDP = 1 << 6;
3761 const SMEP = 1 << 7;
3763 const BMI2 = 1 << 8;
3765 const REP_MOVSB_STOSB = 1 << 9;
3767 const INVPCID = 1 << 10;
3769 const RTM = 1 << 11;
3771 const RDTM = 1 << 12;
3773 const DEPRECATE_FPU_CS_DS = 1 << 13;
3775 const MPX = 1 << 14;
3777 const RDTA = 1 << 15;
3779 const AVX512F = 1 << 16;
3781 const AVX512DQ = 1 << 17;
3783 const RDSEED = 1 << 18;
3785 const ADX = 1 << 19;
3787 const SMAP = 1 << 20;
3789 const AVX512_IFMA = 1 << 21;
3791 const CLFLUSHOPT = 1 << 23;
3794 const CLWB = 1 << 24;
3796 const PROCESSOR_TRACE = 1 << 25;
3798 const AVX512PF = 1 << 26;
3800 const AVX512ER = 1 << 27;
3802 const AVX512CD = 1 << 28;
3804 const SHA = 1 << 29;
3806 const AVX512BW = 1 << 30;
3808 const AVX512VL = 1 << 31;
3810 }
3811}
3812
3813bitflags! {
3814 #[repr(transparent)]
3815 #[derive(Debug, Clone, Copy, PartialEq, Eq)]
3816 struct ExtendedFeaturesEcx: u32 {
3817 const PREFETCHWT1 = 1 << 0;
3819 const AVX512VBMI = 1 << 1;
3821 const UMIP = 1 << 2;
3823 const PKU = 1 << 3;
3825 const OSPKE = 1 << 4;
3827 const WAITPKG = 1 << 5;
3829 const AVX512VBMI2 = 1 << 6;
3831 const CETSS = 1 << 7;
3835 const GFNI = 1 << 8;
3837 const VAES = 1 << 9;
3839 const VPCLMULQDQ = 1 << 10;
3841 const AVX512VNNI = 1 << 11;
3843 const AVX512BITALG = 1 << 12;
3845 const TMEEN = 1 << 13;
3848 const AVX512VPOPCNTDQ = 1 << 14;
3850
3851 const LA57 = 1 << 16;
3855
3856 const RDPID = 1 << 22;
3860
3861 const SGX_LC = 1 << 30;
3865 }
3866}
3867
3868bitflags! {
3869 #[repr(transparent)]
3870 #[derive(Debug, Clone, Copy, PartialEq, Eq)]
3871 struct ExtendedFeaturesEdx: u32 {
3872 const AVX512_4VNNIW = 1 << 2;
3874 const AVX512_4FMAPS = 1 << 3;
3876 const AVX512_VP2INTERSECT = 1 << 8;
3878 const AMX_BF16 = 1 << 22;
3880 const AVX512_FP16 = 1 << 23;
3882 const AMX_TILE = 1 << 24;
3884 const AMX_INT8 = 1 << 25;
3886 }
3887}
3888
3889pub struct DirectCacheAccessInfo {
3894 eax: u32,
3895}
3896
3897impl DirectCacheAccessInfo {
3898 pub fn get_dca_cap_value(&self) -> u32 {
3900 self.eax
3901 }
3902}
3903
3904impl Debug for DirectCacheAccessInfo {
3905 fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
3906 f.debug_struct("DirectCacheAccessInfo")
3907 .field("dca_cap_value", &self.get_dca_cap_value())
3908 .finish()
3909 }
3910}
3911
3912pub struct PerformanceMonitoringInfo {
3917 eax: u32,
3918 ebx: PerformanceMonitoringFeaturesEbx,
3919 _ecx: u32,
3920 edx: u32,
3921}
3922
3923impl PerformanceMonitoringInfo {
3924 pub fn version_id(&self) -> u8 {
3926 get_bits(self.eax, 0, 7) as u8
3927 }
3928
3929 pub fn number_of_counters(&self) -> u8 {
3931 get_bits(self.eax, 8, 15) as u8
3932 }
3933
3934 pub fn counter_bit_width(&self) -> u8 {
3936 get_bits(self.eax, 16, 23) as u8
3937 }
3938
3939 pub fn ebx_length(&self) -> u8 {
3941 get_bits(self.eax, 24, 31) as u8
3942 }
3943
3944 pub fn fixed_function_counters(&self) -> u8 {
3946 get_bits(self.edx, 0, 4) as u8
3947 }
3948
3949 pub fn fixed_function_counters_bit_width(&self) -> u8 {
3951 get_bits(self.edx, 5, 12) as u8
3952 }
3953
3954 check_bit_fn!(
3955 doc = "AnyThread deprecation",
3956 has_any_thread_deprecation,
3957 edx,
3958 15
3959 );
3960
3961 check_flag!(
3962 doc = "Core cycle event not available if 1.",
3963 is_core_cyc_ev_unavailable,
3964 ebx,
3965 PerformanceMonitoringFeaturesEbx::CORE_CYC_EV_UNAVAILABLE
3966 );
3967
3968 check_flag!(
3969 doc = "Instruction retired event not available if 1.",
3970 is_inst_ret_ev_unavailable,
3971 ebx,
3972 PerformanceMonitoringFeaturesEbx::INST_RET_EV_UNAVAILABLE
3973 );
3974
3975 check_flag!(
3976 doc = "Reference cycles event not available if 1.",
3977 is_ref_cycle_ev_unavailable,
3978 ebx,
3979 PerformanceMonitoringFeaturesEbx::REF_CYC_EV_UNAVAILABLE
3980 );
3981
3982 check_flag!(
3983 doc = "Last-level cache reference event not available if 1.",
3984 is_cache_ref_ev_unavailable,
3985 ebx,
3986 PerformanceMonitoringFeaturesEbx::CACHE_REF_EV_UNAVAILABLE
3987 );
3988
3989 check_flag!(
3990 doc = "Last-level cache misses event not available if 1.",
3991 is_ll_cache_miss_ev_unavailable,
3992 ebx,
3993 PerformanceMonitoringFeaturesEbx::LL_CACHE_MISS_EV_UNAVAILABLE
3994 );
3995
3996 check_flag!(
3997 doc = "Branch instruction retired event not available if 1.",
3998 is_branch_inst_ret_ev_unavailable,
3999 ebx,
4000 PerformanceMonitoringFeaturesEbx::BRANCH_INST_RET_EV_UNAVAILABLE
4001 );
4002
4003 check_flag!(
4004 doc = "Branch mispredict retired event not available if 1.",
4005 is_branch_midpred_ev_unavailable,
4006 ebx,
4007 PerformanceMonitoringFeaturesEbx::BRANCH_MISPRED_EV_UNAVAILABLE
4008 );
4009}
4010
4011impl Debug for PerformanceMonitoringInfo {
4012 fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
4013 f.debug_struct("PerformanceMonitoringInfo")
4014 .field("version_id", &self.version_id())
4015 .field("number_of_counters", &self.number_of_counters())
4016 .field("counter_bit_width", &self.counter_bit_width())
4017 .field("ebx_length", &self.ebx_length())
4018 .field("fixed_function_counters", &self.fixed_function_counters())
4019 .field(
4020 "fixed_function_counters_bit_width",
4021 &self.fixed_function_counters_bit_width(),
4022 )
4023 .finish()
4024 }
4025}
4026
4027bitflags! {
4028 #[repr(transparent)]
4029 #[derive(Debug, Clone, Copy, PartialEq, Eq)]
4030 struct PerformanceMonitoringFeaturesEbx: u32 {
4031 const CORE_CYC_EV_UNAVAILABLE = 1 << 0;
4033 const INST_RET_EV_UNAVAILABLE = 1 << 1;
4035 const REF_CYC_EV_UNAVAILABLE = 1 << 2;
4037 const CACHE_REF_EV_UNAVAILABLE = 1 << 3;
4039 const LL_CACHE_MISS_EV_UNAVAILABLE = 1 << 4;
4041 const BRANCH_INST_RET_EV_UNAVAILABLE = 1 << 5;
4043 const BRANCH_MISPRED_EV_UNAVAILABLE = 1 << 6;
4045 }
4046}
4047
4048#[derive(Clone)]
4057pub struct ExtendedTopologyIter<R: CpuIdReader> {
4058 read: R,
4059 level: u32,
4060 is_v2: bool,
4061}
4062
4063#[derive(PartialEq, Eq)]
4067pub struct ExtendedTopologyLevel {
4068 eax: u32,
4069 ebx: u32,
4070 ecx: u32,
4071 edx: u32,
4072}
4073
4074impl fmt::Debug for ExtendedTopologyLevel {
4075 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
4076 f.debug_struct("ExtendedTopologyLevel")
4077 .field("processors", &self.processors())
4078 .field("number", &self.level_number())
4079 .field("type", &self.level_type())
4080 .field("x2apic_id", &self.x2apic_id())
4081 .field("next_apic_id", &self.shift_right_for_next_apic_id())
4082 .finish()
4083 }
4084}
4085
4086impl ExtendedTopologyLevel {
4087 pub fn processors(&self) -> u16 {
4090 get_bits(self.ebx, 0, 15) as u16
4091 }
4092
4093 pub fn level_number(&self) -> u8 {
4095 get_bits(self.ecx, 0, 7) as u8
4096 }
4097
4098 pub fn level_type(&self) -> TopologyType {
4100 match get_bits(self.ecx, 8, 15) {
4101 0 => TopologyType::Invalid,
4102 1 => TopologyType::SMT,
4103 2 => TopologyType::Core,
4104 3 => TopologyType::Module,
4105 4 => TopologyType::Tile,
4106 5 => TopologyType::Die,
4107 _ => unreachable!(),
4108 }
4109 }
4110
4111 pub fn x2apic_id(&self) -> u32 {
4113 self.edx
4114 }
4115
4116 pub fn shift_right_for_next_apic_id(&self) -> u32 {
4119 get_bits(self.eax, 0, 4)
4120 }
4121}
4122
4123#[derive(PartialEq, Eq, Debug)]
4125pub enum TopologyType {
4126 Invalid = 0,
4127 SMT = 1,
4129 Core = 2,
4130 Module = 3,
4131 Tile = 4,
4132 Die = 5,
4133}
4134
4135impl fmt::Display for TopologyType {
4136 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
4137 let data = match self {
4138 TopologyType::Invalid => "Invalid",
4139 TopologyType::SMT => "SMT",
4140 TopologyType::Core => "Core",
4141 TopologyType::Module => "Module",
4142 TopologyType::Tile => "Tile",
4143 TopologyType::Die => "Die",
4144 };
4145
4146 f.write_str(data)
4147 }
4148}
4149
4150impl<R: CpuIdReader> Iterator for ExtendedTopologyIter<R> {
4151 type Item = ExtendedTopologyLevel;
4152
4153 fn next(&mut self) -> Option<ExtendedTopologyLevel> {
4154 let res = if self.is_v2 {
4155 self.read.cpuid2(EAX_EXTENDED_TOPOLOGY_INFO_V2, self.level)
4156 } else {
4157 self.read.cpuid2(EAX_EXTENDED_TOPOLOGY_INFO, self.level)
4158 };
4159 self.level += 1;
4160
4161 let et = ExtendedTopologyLevel {
4162 eax: res.eax,
4163 ebx: res.ebx,
4164 ecx: res.ecx,
4165 edx: res.edx,
4166 };
4167
4168 match et.level_type() {
4169 TopologyType::Invalid => None,
4170 _ => Some(et),
4171 }
4172 }
4173}
4174
4175impl<R: CpuIdReader> Debug for ExtendedTopologyIter<R> {
4176 fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
4177 let mut debug = f.debug_list();
4178 self.clone().for_each(|ref item| {
4179 debug.entry(item);
4180 });
4181 debug.finish()
4182 }
4183}
4184
4185bitflags! {
4186 #[repr(transparent)]
4187 #[derive(Debug, Clone, Copy, PartialEq, Eq)]
4188 struct ExtendedStateInfoXCR0Flags: u32 {
4189 const LEGACY_X87 = 1 << 0;
4191
4192 const SSE128 = 1 << 1;
4194
4195 const AVX256 = 1 << 2;
4197
4198 const MPX_BNDREGS = 1 << 3;
4200
4201 const MPX_BNDCSR = 1 << 4;
4203
4204 const AVX512_OPMASK = 1 << 5;
4206
4207 const AVX512_ZMM_HI256 = 1 << 6;
4209
4210 const AVX512_ZMM_HI16 = 1 << 7;
4212
4213 const PKRU = 1 << 9;
4215
4216 const IA32_XSS_HDC = 1 << 13;
4218
4219 const AMX_TILECFG = 1 << 17;
4221
4222 const AMX_TILEDATA = 1 << 18;
4224 }
4225}
4226
4227bitflags! {
4228 #[repr(transparent)]
4229 #[derive(Debug, Clone, Copy, PartialEq, Eq)]
4230 struct ExtendedStateInfoXSSFlags: u32 {
4231 const PT = 1 << 8;
4233
4234 const PASID = 1 << 10;
4236
4237 const CET_USER = 1 << 11;
4239
4240 const CET_SUPERVISOR = 1 << 12;
4242
4243 const HDC = 1 << 13;
4245
4246 const UINTR = 1 << 14;
4248
4249 const LBR = 1 << 15;
4251
4252 const HWP = 1 << 16;
4254 }
4255}
4256
4257pub struct ExtendedStateInfo<R: CpuIdReader> {
4262 read: R,
4263 eax: ExtendedStateInfoXCR0Flags,
4264 ebx: u32,
4265 ecx: u32,
4266 _edx: u32,
4267 eax1: u32,
4268 ebx1: u32,
4269 ecx1: ExtendedStateInfoXSSFlags,
4270 _edx1: u32,
4271}
4272
4273impl<F: CpuIdReader> ExtendedStateInfo<F> {
4274 check_flag!(
4275 doc = "Support for legacy x87 in XCR0.",
4276 xcr0_supports_legacy_x87,
4277 eax,
4278 ExtendedStateInfoXCR0Flags::LEGACY_X87
4279 );
4280
4281 check_flag!(
4282 doc = "Support for SSE 128-bit in XCR0.",
4283 xcr0_supports_sse_128,
4284 eax,
4285 ExtendedStateInfoXCR0Flags::SSE128
4286 );
4287
4288 check_flag!(
4289 doc = "Support for AVX 256-bit in XCR0.",
4290 xcr0_supports_avx_256,
4291 eax,
4292 ExtendedStateInfoXCR0Flags::AVX256
4293 );
4294
4295 check_flag!(
4296 doc = "Support for MPX BNDREGS in XCR0.",
4297 xcr0_supports_mpx_bndregs,
4298 eax,
4299 ExtendedStateInfoXCR0Flags::MPX_BNDREGS
4300 );
4301
4302 check_flag!(
4303 doc = "Support for MPX BNDCSR in XCR0.",
4304 xcr0_supports_mpx_bndcsr,
4305 eax,
4306 ExtendedStateInfoXCR0Flags::MPX_BNDCSR
4307 );
4308
4309 check_flag!(
4310 doc = "Support for AVX512 OPMASK in XCR0.",
4311 xcr0_supports_avx512_opmask,
4312 eax,
4313 ExtendedStateInfoXCR0Flags::AVX512_OPMASK
4314 );
4315
4316 check_flag!(
4317 doc = "Support for AVX512 ZMM Hi256 XCR0.",
4318 xcr0_supports_avx512_zmm_hi256,
4319 eax,
4320 ExtendedStateInfoXCR0Flags::AVX512_ZMM_HI256
4321 );
4322
4323 check_flag!(
4324 doc = "Support for AVX512 ZMM Hi16 in XCR0.",
4325 xcr0_supports_avx512_zmm_hi16,
4326 eax,
4327 ExtendedStateInfoXCR0Flags::AVX512_ZMM_HI16
4328 );
4329
4330 check_flag!(
4331 doc = "Support for PKRU in XCR0.",
4332 xcr0_supports_pkru,
4333 eax,
4334 ExtendedStateInfoXCR0Flags::PKRU
4335 );
4336
4337 check_flag!(
4338 doc = "Support for PT in IA32_XSS.",
4339 ia32_xss_supports_pt,
4340 ecx1,
4341 ExtendedStateInfoXSSFlags::PT
4342 );
4343
4344 check_flag!(
4345 doc = "Support for HDC in IA32_XSS.",
4346 ia32_xss_supports_hdc,
4347 ecx1,
4348 ExtendedStateInfoXSSFlags::HDC
4349 );
4350
4351 pub fn xsave_area_size_enabled_features(&self) -> u32 {
4355 self.ebx
4356 }
4357
4358 pub fn xsave_area_size_supported_features(&self) -> u32 {
4362 self.ecx
4363 }
4364
4365 pub fn has_xsaveopt(&self) -> bool {
4367 self.eax1 & 0x1 > 0
4368 }
4369
4370 pub fn has_xsavec(&self) -> bool {
4372 self.eax1 & 0b10 > 0
4373 }
4374
4375 pub fn has_xgetbv(&self) -> bool {
4377 self.eax1 & 0b100 > 0
4378 }
4379
4380 pub fn has_xsaves_xrstors(&self) -> bool {
4382 self.eax1 & 0b1000 > 0
4383 }
4384
4385 pub fn xsave_size(&self) -> u32 {
4387 self.ebx1
4388 }
4389
4390 pub fn iter(&self) -> ExtendedStateIter<F> {
4392 ExtendedStateIter {
4393 read: self.read.clone(),
4394 level: 1,
4395 supported_xcr0: self.eax.bits(),
4396 supported_xss: self.ecx1.bits(),
4397 }
4398 }
4399}
4400
4401impl<R: CpuIdReader> Debug for ExtendedStateInfo<R> {
4402 fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
4403 f.debug_struct("ExtendedStateInfo")
4404 .field("eax", &self.eax)
4405 .field("ecx1", &self.ecx1)
4406 .field(
4407 "xsave_area_size_enabled_features",
4408 &self.xsave_area_size_enabled_features(),
4409 )
4410 .field(
4411 "xsave_area_size_supported_features",
4412 &self.xsave_area_size_supported_features(),
4413 )
4414 .field("has_xsaveopt", &self.has_xsaveopt())
4415 .field("has_xsavec", &self.has_xsavec())
4416 .field("has_xgetbv", &self.has_xgetbv())
4417 .field("has_xsaves_xrstors", &self.has_xsaves_xrstors())
4418 .field("xsave_size", &self.xsave_size())
4419 .field("extended_state_iter", &self.iter())
4420 .finish()
4421 }
4422}
4423
4424#[derive(Clone)]
4426pub struct ExtendedStateIter<R: CpuIdReader> {
4427 read: R,
4428 level: u32,
4429 supported_xcr0: u32,
4430 supported_xss: u32,
4431}
4432
4433impl<R: CpuIdReader> Iterator for ExtendedStateIter<R> {
4440 type Item = ExtendedState;
4441
4442 fn next(&mut self) -> Option<ExtendedState> {
4443 self.level += 1;
4444 if self.level > 31 {
4445 return None;
4446 }
4447
4448 let bit = 1 << self.level;
4449 if (self.supported_xcr0 & bit > 0) || (self.supported_xss & bit > 0) {
4450 let res = self.read.cpuid2(EAX_EXTENDED_STATE_INFO, self.level);
4451 return Some(ExtendedState {
4452 subleaf: self.level,
4453 eax: res.eax,
4454 ebx: res.ebx,
4455 ecx: res.ecx,
4456 });
4457 }
4458
4459 self.next()
4460 }
4461}
4462
4463impl<R: CpuIdReader> Debug for ExtendedStateIter<R> {
4464 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
4465 let mut debug = f.debug_list();
4466 self.clone().for_each(|ref item| {
4467 debug.entry(item);
4468 });
4469 debug.finish()
4470 }
4471}
4472
4473#[derive(PartialEq, Eq, Debug)]
4475#[repr(u32)]
4476pub enum ExtendedRegisterType {
4477 Avx,
4478 MpxBndregs,
4479 MpxBndcsr,
4480 Avx512Opmask,
4481 Avx512ZmmHi256,
4482 Avx512ZmmHi16,
4483 Pt,
4484 Pkru,
4485 Hdc,
4486 Unknown(u32),
4487}
4488
4489impl From<u32> for ExtendedRegisterType {
4490 fn from(value: u32) -> ExtendedRegisterType {
4491 match value {
4492 0x2 => ExtendedRegisterType::Avx,
4493 0x3 => ExtendedRegisterType::MpxBndregs,
4494 0x4 => ExtendedRegisterType::MpxBndcsr,
4495 0x5 => ExtendedRegisterType::Avx512Opmask,
4496 0x6 => ExtendedRegisterType::Avx512ZmmHi256,
4497 0x7 => ExtendedRegisterType::Avx512ZmmHi16,
4498 0x8 => ExtendedRegisterType::Pt,
4499 0x9 => ExtendedRegisterType::Pkru,
4500 0xd => ExtendedRegisterType::Hdc,
4501 x => ExtendedRegisterType::Unknown(x),
4502 }
4503 }
4504}
4505
4506impl fmt::Display for ExtendedRegisterType {
4507 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
4508 let data = match self {
4509 ExtendedRegisterType::Avx => "AVX/YMM",
4510 ExtendedRegisterType::MpxBndregs => "MPX BNDREGS",
4511 ExtendedRegisterType::MpxBndcsr => "MPX BNDCSR",
4512 ExtendedRegisterType::Avx512Opmask => "AVX-512 opmask",
4513 ExtendedRegisterType::Avx512ZmmHi256 => "AVX-512 ZMM_Hi256",
4514 ExtendedRegisterType::Avx512ZmmHi16 => "AVX-512 Hi16_ZMM",
4515 ExtendedRegisterType::Pkru => "PKRU",
4516 ExtendedRegisterType::Pt => "PT",
4517 ExtendedRegisterType::Hdc => "HDC",
4518 ExtendedRegisterType::Unknown(t) => {
4519 return write!(f, "Unknown({})", t);
4520 }
4521 };
4522
4523 f.write_str(data)
4524 }
4525}
4526
4527#[derive(PartialEq, Eq, Debug)]
4529pub enum ExtendedRegisterStateLocation {
4530 Xcr0,
4531 Ia32Xss,
4532}
4533
4534impl fmt::Display for ExtendedRegisterStateLocation {
4535 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
4536 let data = match self {
4537 ExtendedRegisterStateLocation::Xcr0 => "XCR0 (user state)",
4538 ExtendedRegisterStateLocation::Ia32Xss => "IA32_XSS (supervisor state)",
4539 };
4540
4541 f.write_str(data)
4542 }
4543}
4544
4545pub struct ExtendedState {
4547 pub subleaf: u32,
4548 eax: u32,
4549 ebx: u32,
4550 ecx: u32,
4551}
4552
4553impl ExtendedState {
4554 pub fn register(&self) -> ExtendedRegisterType {
4556 self.subleaf.into()
4557 }
4558
4559 pub fn size(&self) -> u32 {
4563 self.eax
4564 }
4565
4566 pub fn offset(&self) -> u32 {
4569 self.ebx
4570 }
4571
4572 pub fn location(&self) -> ExtendedRegisterStateLocation {
4573 if self.is_in_xcr0() {
4574 ExtendedRegisterStateLocation::Xcr0
4575 } else {
4576 ExtendedRegisterStateLocation::Ia32Xss
4577 }
4578 }
4579
4580 pub fn is_in_ia32_xss(&self) -> bool {
4586 self.ecx & 0b1 > 0
4587 }
4588
4589 pub fn is_in_xcr0(&self) -> bool {
4594 self.ecx & 0b1 == 0
4595 }
4596
4597 pub fn is_compacted_format(&self) -> bool {
4602 self.ecx & 0b10 > 0
4603 }
4604}
4605
4606impl Debug for ExtendedState {
4607 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
4608 f.debug_struct("ExtendedState")
4609 .field("size", &self.size())
4610 .field("offset", &self.offset())
4611 .field("is_in_ia32_xss", &self.is_in_ia32_xss())
4612 .field("is_in_xcr0", &self.is_in_xcr0())
4613 .field("is_compacted_format", &self.is_compacted_format())
4614 .finish()
4615 }
4616}
4617
4618pub struct RdtMonitoringInfo<R: CpuIdReader> {
4624 read: R,
4625 ebx: u32,
4626 edx: u32,
4627}
4628
4629impl<R: CpuIdReader> RdtMonitoringInfo<R> {
4630 pub fn rmid_range(&self) -> u32 {
4632 self.ebx
4633 }
4634
4635 check_bit_fn!(
4636 doc = "Supports L3 Cache Intel RDT Monitoring.",
4637 has_l3_monitoring,
4638 edx,
4639 1
4640 );
4641
4642 pub fn l3_monitoring(&self) -> Option<L3MonitoringInfo> {
4644 if self.has_l3_monitoring() {
4645 let res = self.read.cpuid2(EAX_RDT_MONITORING, 1);
4646 Some(L3MonitoringInfo {
4647 ebx: res.ebx,
4648 ecx: res.ecx,
4649 edx: res.edx,
4650 })
4651 } else {
4652 None
4653 }
4654 }
4655}
4656
4657impl<R: CpuIdReader> Debug for RdtMonitoringInfo<R> {
4658 fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
4659 f.debug_struct("RdtMonitoringInfo")
4660 .field("rmid_range", &self.rmid_range())
4661 .field("l3_monitoring", &self.l3_monitoring())
4662 .finish()
4663 }
4664}
4665
4666pub struct L3MonitoringInfo {
4668 ebx: u32,
4669 ecx: u32,
4670 edx: u32,
4671}
4672
4673impl L3MonitoringInfo {
4674 pub fn conversion_factor(&self) -> u32 {
4676 self.ebx
4677 }
4678
4679 pub fn maximum_rmid_range(&self) -> u32 {
4681 self.ecx
4682 }
4683
4684 check_bit_fn!(
4685 doc = "Supports occupancy monitoring.",
4686 has_occupancy_monitoring,
4687 edx,
4688 0
4689 );
4690
4691 check_bit_fn!(
4692 doc = "Supports total bandwidth monitoring.",
4693 has_total_bandwidth_monitoring,
4694 edx,
4695 1
4696 );
4697
4698 check_bit_fn!(
4699 doc = "Supports local bandwidth monitoring.",
4700 has_local_bandwidth_monitoring,
4701 edx,
4702 2
4703 );
4704}
4705
4706impl Debug for L3MonitoringInfo {
4707 fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
4708 f.debug_struct("L3MonitoringInfo")
4709 .field("conversion_factor", &self.conversion_factor())
4710 .field("maximum_rmid_range", &self.maximum_rmid_range())
4711 .finish()
4712 }
4713}
4714
4715pub struct RdtAllocationInfo<R: CpuIdReader> {
4720 read: R,
4721 ebx: u32,
4722}
4723
4724impl<R: CpuIdReader> RdtAllocationInfo<R> {
4725 check_bit_fn!(doc = "Supports L3 Cache Allocation.", has_l3_cat, ebx, 1);
4726
4727 check_bit_fn!(doc = "Supports L2 Cache Allocation.", has_l2_cat, ebx, 2);
4728
4729 check_bit_fn!(
4730 doc = "Supports Memory Bandwidth Allocation.",
4731 has_memory_bandwidth_allocation,
4732 ebx,
4733 3
4734 );
4735
4736 pub fn l3_cat(&self) -> Option<L3CatInfo> {
4738 if self.has_l3_cat() {
4739 let res = self.read.cpuid2(EAX_RDT_ALLOCATION, 1);
4740 Some(L3CatInfo {
4741 eax: res.eax,
4742 ebx: res.ebx,
4743 ecx: res.ecx,
4744 edx: res.edx,
4745 })
4746 } else {
4747 None
4748 }
4749 }
4750
4751 pub fn l2_cat(&self) -> Option<L2CatInfo> {
4753 if self.has_l2_cat() {
4754 let res = self.read.cpuid2(EAX_RDT_ALLOCATION, 2);
4755 Some(L2CatInfo {
4756 eax: res.eax,
4757 ebx: res.ebx,
4758 edx: res.edx,
4759 })
4760 } else {
4761 None
4762 }
4763 }
4764
4765 pub fn memory_bandwidth_allocation(&self) -> Option<MemBwAllocationInfo> {
4767 if self.has_memory_bandwidth_allocation() {
4768 let res = self.read.cpuid2(EAX_RDT_ALLOCATION, 3);
4769 Some(MemBwAllocationInfo {
4770 eax: res.eax,
4771 ecx: res.ecx,
4772 edx: res.edx,
4773 })
4774 } else {
4775 None
4776 }
4777 }
4778}
4779
4780impl<R: CpuIdReader> Debug for RdtAllocationInfo<R> {
4781 fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
4782 f.debug_struct("RdtAllocationInfo")
4783 .field("l3_cat", &self.l3_cat())
4784 .field("l2_cat", &self.l2_cat())
4785 .field(
4786 "memory_bandwidth_allocation",
4787 &self.memory_bandwidth_allocation(),
4788 )
4789 .finish()
4790 }
4791}
4792
4793pub struct L3CatInfo {
4795 eax: u32,
4796 ebx: u32,
4797 ecx: u32,
4798 edx: u32,
4799}
4800
4801impl L3CatInfo {
4802 pub fn capacity_mask_length(&self) -> u8 {
4804 (get_bits(self.eax, 0, 4) + 1) as u8
4805 }
4806
4807 pub fn isolation_bitmap(&self) -> u32 {
4809 self.ebx
4810 }
4811
4812 pub fn highest_cos(&self) -> u16 {
4814 get_bits(self.edx, 0, 15) as u16
4815 }
4816
4817 check_bit_fn!(
4818 doc = "Is Code and Data Prioritization Technology supported?",
4819 has_code_data_prioritization,
4820 ecx,
4821 2
4822 );
4823}
4824
4825impl Debug for L3CatInfo {
4826 fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
4827 f.debug_struct("L3CatInfo")
4828 .field("capacity_mask_length", &self.capacity_mask_length())
4829 .field("isolation_bitmap", &self.isolation_bitmap())
4830 .field("highest_cos", &self.highest_cos())
4831 .finish()
4832 }
4833}
4834
4835#[derive(Eq, PartialEq)]
4837pub struct L2CatInfo {
4838 eax: u32,
4839 ebx: u32,
4840 edx: u32,
4841}
4842
4843impl L2CatInfo {
4844 pub fn capacity_mask_length(&self) -> u8 {
4846 (get_bits(self.eax, 0, 4) + 1) as u8
4847 }
4848
4849 pub fn isolation_bitmap(&self) -> u32 {
4851 self.ebx
4852 }
4853
4854 pub fn highest_cos(&self) -> u16 {
4856 get_bits(self.edx, 0, 15) as u16
4857 }
4858}
4859
4860impl Debug for L2CatInfo {
4861 fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
4862 f.debug_struct("L2CatInfo")
4863 .field("capacity_mask_length", &self.capacity_mask_length())
4864 .field("isolation_bitmap", &self.isolation_bitmap())
4865 .field("highest_cos", &self.highest_cos())
4866 .finish()
4867 }
4868}
4869
4870#[derive(Eq, PartialEq)]
4872pub struct MemBwAllocationInfo {
4873 eax: u32,
4874 ecx: u32,
4875 edx: u32,
4876}
4877
4878impl MemBwAllocationInfo {
4879 pub fn max_hba_throttling(&self) -> u16 {
4881 (get_bits(self.eax, 0, 11) + 1) as u16
4882 }
4883
4884 pub fn highest_cos(&self) -> u16 {
4886 get_bits(self.edx, 0, 15) as u16
4887 }
4888
4889 check_bit_fn!(
4890 doc = "Reports whether the response of the delay values is linear.",
4891 has_linear_response_delay,
4892 ecx,
4893 2
4894 );
4895}
4896
4897impl Debug for MemBwAllocationInfo {
4898 fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
4899 f.debug_struct("MemBwAllocationInfo")
4900 .field("max_hba_throttling", &self.max_hba_throttling())
4901 .field("highest_cos", &self.highest_cos())
4902 .field(
4903 "has_linear_response_delay",
4904 &self.has_linear_response_delay(),
4905 )
4906 .finish()
4907 }
4908}
4909
4910pub struct SgxInfo<R: CpuIdReader> {
4917 read: R,
4918 eax: u32,
4919 ebx: u32,
4920 _ecx: u32,
4921 edx: u32,
4922 eax1: u32,
4923 ebx1: u32,
4924 ecx1: u32,
4925 edx1: u32,
4926}
4927
4928impl<F: CpuIdReader> SgxInfo<F> {
4929 check_bit_fn!(doc = "Has SGX1 support.", has_sgx1, eax, 0);
4930 check_bit_fn!(doc = "Has SGX2 support.", has_sgx2, eax, 1);
4931
4932 check_bit_fn!(
4933 doc = "Supports ENCLV instruction leaves EINCVIRTCHILD, EDECVIRTCHILD, and ESETCONTEXT.",
4934 has_enclv_leaves_einvirtchild_edecvirtchild_esetcontext,
4935 eax,
4936 5
4937 );
4938
4939 check_bit_fn!(
4940 doc = "Supports ENCLS instruction leaves ETRACKC, ERDINFO, ELDBC, and ELDUC.",
4941 has_encls_leaves_etrackc_erdinfo_eldbc_elduc,
4942 eax,
4943 6
4944 );
4945
4946 pub fn miscselect(&self) -> u32 {
4948 self.ebx
4949 }
4950
4951 pub fn max_enclave_size_non_64bit(&self) -> u8 {
4953 get_bits(self.edx, 0, 7) as u8
4954 }
4955
4956 pub fn max_enclave_size_64bit(&self) -> u8 {
4958 get_bits(self.edx, 8, 15) as u8
4959 }
4960
4961 pub fn secs_attributes(&self) -> (u64, u64) {
4963 let lower = self.eax1 as u64 | (self.ebx1 as u64) << 32;
4964 let upper = self.ecx1 as u64 | (self.edx1 as u64) << 32;
4965 (lower, upper)
4966 }
4967 pub fn iter(&self) -> SgxSectionIter<F> {
4969 SgxSectionIter {
4970 read: self.read.clone(),
4971 current: 2,
4972 }
4973 }
4974}
4975
4976impl<R: CpuIdReader> Debug for SgxInfo<R> {
4977 fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
4978 f.debug_struct("SgxInfo")
4979 .field("has_sgx1", &self.has_sgx1())
4980 .field("has_sgx2", &self.has_sgx2())
4981 .field("miscselect", &self.miscselect())
4982 .field(
4983 "max_enclave_size_non_64bit",
4984 &self.max_enclave_size_non_64bit(),
4985 )
4986 .field("max_enclave_size_64bit", &self.max_enclave_size_64bit())
4987 .field(
4988 "has_encls_leaves_etrackc_erdinfo_eldbc_elduc",
4989 &self.has_encls_leaves_etrackc_erdinfo_eldbc_elduc(),
4990 )
4991 .field(
4992 "has_enclv_leaves_einvirtchild_edecvirtchild_esetcontext",
4993 &self.has_enclv_leaves_einvirtchild_edecvirtchild_esetcontext(),
4994 )
4995 .field("sgx_section_iter", &self.iter())
4996 .finish()
4997 }
4998}
4999
5000#[derive(Clone)]
5002pub struct SgxSectionIter<R: CpuIdReader> {
5003 read: R,
5004 current: u32,
5005}
5006
5007impl<R: CpuIdReader> Iterator for SgxSectionIter<R> {
5008 type Item = SgxSectionInfo;
5009
5010 fn next(&mut self) -> Option<SgxSectionInfo> {
5011 let res = self.read.cpuid2(EAX_SGX, self.current);
5012 self.current += 1;
5013 match get_bits(res.eax, 0, 3) {
5014 0b0001 => Some(SgxSectionInfo::Epc(EpcSection {
5015 eax: res.eax,
5016 ebx: res.ebx,
5017 ecx: res.ecx,
5018 edx: res.edx,
5019 })),
5020 _ => None,
5021 }
5022 }
5023}
5024
5025impl<R: CpuIdReader> Debug for SgxSectionIter<R> {
5026 fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
5027 let mut debug = f.debug_list();
5028 self.clone().for_each(|ref item| {
5029 debug.entry(item);
5030 });
5031 debug.finish()
5032 }
5033}
5034
5035#[derive(Debug)]
5039pub enum SgxSectionInfo {
5040 Epc(EpcSection),
5042}
5043
5044#[derive(Debug)]
5046pub struct EpcSection {
5047 eax: u32,
5048 ebx: u32,
5049 ecx: u32,
5050 edx: u32,
5051}
5052
5053impl EpcSection {
5054 pub fn physical_base(&self) -> u64 {
5056 let lower = (get_bits(self.eax, 12, 31) << 12) as u64;
5057 let upper = (get_bits(self.ebx, 0, 19) as u64) << 32;
5058 lower | upper
5059 }
5060
5061 pub fn size(&self) -> u64 {
5063 let lower = (get_bits(self.ecx, 12, 31) << 12) as u64;
5064 let upper = (get_bits(self.edx, 0, 19) as u64) << 32;
5065 lower | upper
5066 }
5067}
5068
5069pub struct ProcessorTraceInfo {
5074 _eax: u32,
5075 ebx: u32,
5076 ecx: u32,
5077 _edx: u32,
5078 leaf1: Option<CpuIdResult>,
5079}
5080
5081impl ProcessorTraceInfo {
5082 check_bit_fn!(
5084 doc = "If true, Indicates that IA32_RTIT_CTL.CR3Filter can be set to 1, and \
5085 that IA32_RTIT_CR3_MATCH MSR can be accessed.",
5086 has_rtit_cr3_match,
5087 ebx,
5088 0
5089 );
5090 check_bit_fn!(
5091 doc = "If true, Indicates support of Configurable PSB and Cycle-Accurate Mode.",
5092 has_configurable_psb_and_cycle_accurate_mode,
5093 ebx,
5094 1
5095 );
5096 check_bit_fn!(
5097 doc = "If true, Indicates support of IP Filtering, TraceStop filtering, and \
5098 preservation of Intel PT MSRs across warm reset.",
5099 has_ip_tracestop_filtering,
5100 ebx,
5101 2
5102 );
5103 check_bit_fn!(
5104 doc = "If true, Indicates support of MTC timing packet and suppression of \
5105 COFI-based packets.",
5106 has_mtc_timing_packet_coefi_suppression,
5107 ebx,
5108 3
5109 );
5110
5111 check_bit_fn!(
5112 doc = "Indicates support of PTWRITE. Writes can set IA32_RTIT_CTL\\[12\\] (PTWEn \
5113 and IA32_RTIT_CTL\\[5\\] (FUPonPTW), and PTWRITE can generate packets",
5114 has_ptwrite,
5115 ebx,
5116 4
5117 );
5118
5119 check_bit_fn!(
5120 doc = "Support of Power Event Trace. Writes can set IA32_RTIT_CTL\\[4\\] (PwrEvtEn) \
5121 enabling Power Event Trace packet generation.",
5122 has_power_event_trace,
5123 ebx,
5124 5
5125 );
5126
5127 check_bit_fn!(
5129 doc = "If true, Tracing can be enabled with IA32_RTIT_CTL.ToPA = 1, hence \
5130 utilizing the ToPA output scheme; IA32_RTIT_OUTPUT_BASE and \
5131 IA32_RTIT_OUTPUT_MASK_PTRS MSRs can be accessed.",
5132 has_topa,
5133 ecx,
5134 0
5135 );
5136 check_bit_fn!(
5137 doc = "If true, ToPA tables can hold any number of output entries, up to the \
5138 maximum allowed by the MaskOrTableOffset field of \
5139 IA32_RTIT_OUTPUT_MASK_PTRS.",
5140 has_topa_maximum_entries,
5141 ecx,
5142 1
5143 );
5144 check_bit_fn!(
5145 doc = "If true, Indicates support of Single-Range Output scheme.",
5146 has_single_range_output_scheme,
5147 ecx,
5148 2
5149 );
5150 check_bit_fn!(
5151 doc = "If true, Indicates support of output to Trace Transport subsystem.",
5152 has_trace_transport_subsystem,
5153 ecx,
5154 3
5155 );
5156 check_bit_fn!(
5157 doc = "If true, Generated packets which contain IP payloads have LIP values, \
5158 which include the CS base component.",
5159 has_lip_with_cs_base,
5160 ecx,
5161 31
5162 );
5163
5164 pub fn configurable_address_ranges(&self) -> u8 {
5166 self.leaf1.map_or(0, |res| get_bits(res.eax, 0, 2) as u8)
5167 }
5168
5169 pub fn supported_mtc_period_encodings(&self) -> u16 {
5171 self.leaf1.map_or(0, |res| get_bits(res.eax, 16, 31) as u16)
5172 }
5173
5174 pub fn supported_cycle_threshold_value_encodings(&self) -> u16 {
5176 self.leaf1.map_or(0, |res| get_bits(res.ebx, 0, 15) as u16)
5177 }
5178
5179 pub fn supported_psb_frequency_encodings(&self) -> u16 {
5181 self.leaf1.map_or(0, |res| get_bits(res.ebx, 16, 31) as u16)
5182 }
5183}
5184
5185impl Debug for ProcessorTraceInfo {
5186 fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
5187 f.debug_struct("ProcessorTraceInfo")
5188 .field(
5189 "configurable_address_ranges",
5190 &self.configurable_address_ranges(),
5191 )
5192 .field(
5193 "supported_mtc_period_encodings",
5194 &self.supported_mtc_period_encodings(),
5195 )
5196 .field(
5197 "supported_cycle_threshold_value_encodings",
5198 &self.supported_cycle_threshold_value_encodings(),
5199 )
5200 .field(
5201 "supported_psb_frequency_encodings",
5202 &self.supported_psb_frequency_encodings(),
5203 )
5204 .finish()
5205 }
5206}
5207
5208pub struct TscInfo {
5213 eax: u32,
5214 ebx: u32,
5215 ecx: u32,
5216}
5217
5218impl fmt::Debug for TscInfo {
5219 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
5220 f.debug_struct("TscInfo")
5221 .field("denominator", &self.denominator())
5222 .field("numerator", &self.numerator())
5223 .field("nominal_frequency", &self.nominal_frequency())
5224 .field("tsc_frequency", &self.tsc_frequency())
5225 .finish()
5226 }
5227}
5228
5229impl TscInfo {
5230 pub fn denominator(&self) -> u32 {
5232 self.eax
5233 }
5234
5235 pub fn numerator(&self) -> u32 {
5239 self.ebx
5240 }
5241
5242 pub fn nominal_frequency(&self) -> u32 {
5246 self.ecx
5247 }
5248
5249 pub fn tsc_frequency(&self) -> Option<u64> {
5251 if self.nominal_frequency() == 0 || self.numerator() == 0 || self.denominator() == 0 {
5254 return None;
5255 }
5256
5257 Some(self.nominal_frequency() as u64 * self.numerator() as u64 / self.denominator() as u64)
5258 }
5259}
5260
5261pub struct ProcessorFrequencyInfo {
5266 eax: u32,
5267 ebx: u32,
5268 ecx: u32,
5269}
5270
5271impl ProcessorFrequencyInfo {
5272 pub fn processor_base_frequency(&self) -> u16 {
5274 get_bits(self.eax, 0, 15) as u16
5275 }
5276
5277 pub fn processor_max_frequency(&self) -> u16 {
5279 get_bits(self.ebx, 0, 15) as u16
5280 }
5281
5282 pub fn bus_frequency(&self) -> u16 {
5284 get_bits(self.ecx, 0, 15) as u16
5285 }
5286}
5287
5288impl fmt::Debug for ProcessorFrequencyInfo {
5289 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
5290 f.debug_struct("ProcessorFrequencyInfo")
5291 .field("processor_base_frequency", &self.processor_base_frequency())
5292 .field("processor_max_frequency", &self.processor_max_frequency())
5293 .field("bus_frequency", &self.bus_frequency())
5294 .finish()
5295 }
5296}
5297
5298#[derive(Clone)]
5303pub struct DatIter<R: CpuIdReader> {
5304 read: R,
5305 current: u32,
5306 count: u32,
5307}
5308
5309impl<R: CpuIdReader> Iterator for DatIter<R> {
5310 type Item = DatInfo;
5311
5312 fn next(&mut self) -> Option<DatInfo> {
5314 loop {
5315 if self.current > self.count {
5317 return None;
5318 }
5319
5320 let res = self
5321 .read
5322 .cpuid2(EAX_DETERMINISTIC_ADDRESS_TRANSLATION_INFO, self.current);
5323 self.current += 1;
5324
5325 if get_bits(res.edx, 0, 4) == 0 {
5327 continue;
5331 }
5332
5333 return Some(DatInfo {
5334 _eax: res.eax,
5335 ebx: res.ebx,
5336 ecx: res.ecx,
5337 edx: res.edx,
5338 });
5339 }
5340 }
5341}
5342
5343impl<R: CpuIdReader> Debug for DatIter<R> {
5344 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
5345 let mut debug = f.debug_list();
5346 self.clone().for_each(|ref item| {
5347 debug.entry(item);
5348 });
5349 debug.finish()
5350 }
5351}
5352
5353pub struct DatInfo {
5355 _eax: u32,
5356 ebx: u32,
5357 ecx: u32,
5358 edx: u32,
5359}
5360
5361impl DatInfo {
5362 check_bit_fn!(
5363 doc = "4K page size entries supported by this structure",
5364 has_4k_entries,
5365 ebx,
5366 0
5367 );
5368
5369 check_bit_fn!(
5370 doc = "2MB page size entries supported by this structure",
5371 has_2mb_entries,
5372 ebx,
5373 1
5374 );
5375
5376 check_bit_fn!(
5377 doc = "4MB page size entries supported by this structure",
5378 has_4mb_entries,
5379 ebx,
5380 2
5381 );
5382
5383 check_bit_fn!(
5384 doc = "1GB page size entries supported by this structure",
5385 has_1gb_entries,
5386 ebx,
5387 3
5388 );
5389
5390 check_bit_fn!(
5391 doc = "Fully associative structure",
5392 is_fully_associative,
5393 edx,
5394 8
5395 );
5396
5397 pub fn partitioning(&self) -> u8 {
5399 get_bits(self.ebx, 8, 10) as u8
5400 }
5401
5402 pub fn ways(&self) -> u16 {
5404 get_bits(self.ebx, 16, 31) as u16
5405 }
5406
5407 pub fn sets(&self) -> u32 {
5409 self.ecx
5410 }
5411
5412 pub fn cache_type(&self) -> DatType {
5414 match get_bits(self.edx, 0, 4) as u8 {
5415 0b00001 => DatType::DataTLB,
5416 0b00010 => DatType::InstructionTLB,
5417 0b00011 => DatType::UnifiedTLB,
5418 0b00000 => DatType::Null, 0b00100 => DatType::LoadOnly,
5420 0b00101 => DatType::StoreOnly,
5421 _ => DatType::Unknown,
5422 }
5423 }
5424
5425 pub fn cache_level(&self) -> u8 {
5427 get_bits(self.edx, 5, 7) as u8
5428 }
5429
5430 pub fn max_addressable_ids(&self) -> u16 {
5432 (get_bits(self.edx, 14, 25) + 1) as u16
5434 }
5435}
5436
5437impl Debug for DatInfo {
5438 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
5439 f.debug_struct("DatInfo")
5440 .field("has_4k_entries", &self.has_4k_entries())
5441 .field("has_2mb_entries", &self.has_2mb_entries())
5442 .field("has_4mb_entries", &self.has_4mb_entries())
5443 .field("has_1gb_entries", &self.has_1gb_entries())
5444 .field("is_fully_associative", &self.is_fully_associative())
5445 .finish()
5446 }
5447}
5448
5449#[derive(Eq, PartialEq, Debug)]
5451pub enum DatType {
5452 Null = 0b00000,
5454 DataTLB = 0b00001,
5455 InstructionTLB = 0b00010,
5456 UnifiedTLB = 0b00011,
5462 LoadOnly = 0b0100,
5463 StoreOnly = 0b0101,
5464 Unknown,
5465}
5466
5467impl fmt::Display for DatType {
5468 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
5469 let t = match self {
5470 DatType::Null => "invalid (0)",
5471 DatType::DataTLB => "Data TLB",
5472 DatType::InstructionTLB => "Instruction TLB",
5473 DatType::UnifiedTLB => "Unified TLB",
5474 DatType::LoadOnly => "Load Only",
5475 DatType::StoreOnly => "Store Only",
5476 DatType::Unknown => "Unknown",
5477 };
5478 f.write_str(t)
5479 }
5480}
5481
5482pub struct SoCVendorInfo<R: CpuIdReader> {
5487 read: R,
5488 eax: u32,
5490 ebx: u32,
5491 ecx: u32,
5492 edx: u32,
5493}
5494
5495impl<R: CpuIdReader> SoCVendorInfo<R> {
5496 pub fn get_soc_vendor_id(&self) -> u16 {
5497 get_bits(self.ebx, 0, 15) as u16
5498 }
5499
5500 pub fn get_project_id(&self) -> u32 {
5501 self.ecx
5502 }
5503
5504 pub fn get_stepping_id(&self) -> u32 {
5505 self.edx
5506 }
5507
5508 pub fn get_vendor_brand(&self) -> Option<SoCVendorBrand> {
5509 if self.eax >= 3 {
5511 let r1 = self.read.cpuid2(EAX_SOC_VENDOR_INFO, 1);
5512 let r2 = self.read.cpuid2(EAX_SOC_VENDOR_INFO, 2);
5513 let r3 = self.read.cpuid2(EAX_SOC_VENDOR_INFO, 3);
5514 Some(SoCVendorBrand { data: [r1, r2, r3] })
5515 } else {
5516 None
5517 }
5518 }
5519
5520 pub fn get_vendor_attributes(&self) -> Option<SoCVendorAttributesIter<R>> {
5521 if self.eax > 3 {
5522 Some(SoCVendorAttributesIter {
5523 read: self.read.clone(),
5524 count: self.eax,
5525 current: 3,
5526 })
5527 } else {
5528 None
5529 }
5530 }
5531}
5532
5533impl<R: CpuIdReader> fmt::Debug for SoCVendorInfo<R> {
5534 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
5535 f.debug_struct("SoCVendorInfo")
5536 .field("soc_vendor_id", &self.get_soc_vendor_id())
5537 .field("project_id", &self.get_project_id())
5538 .field("stepping_id", &self.get_stepping_id())
5539 .field("vendor_brand", &self.get_vendor_brand())
5540 .field("vendor_attributes", &self.get_vendor_attributes())
5541 .finish()
5542 }
5543}
5544
5545pub struct SoCVendorAttributesIter<R: CpuIdReader> {
5547 read: R,
5548 count: u32,
5549 current: u32,
5550}
5551
5552impl<R: CpuIdReader> fmt::Debug for SoCVendorAttributesIter<R> {
5553 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
5554 f.debug_struct("SocVendorAttributesIter")
5555 .field("count", &self.count)
5556 .field("current", &self.current)
5557 .finish()
5558 }
5559}
5560
5561impl<R: CpuIdReader> Iterator for SoCVendorAttributesIter<R> {
5562 type Item = CpuIdResult;
5563
5564 fn next(&mut self) -> Option<CpuIdResult> {
5566 if self.current > self.count {
5567 return None;
5568 }
5569 self.count += 1;
5570 Some(self.read.cpuid2(EAX_SOC_VENDOR_INFO, self.count))
5571 }
5572}
5573
5574#[derive(Debug, PartialEq, Eq)]
5576#[repr(C)]
5577pub struct SoCVendorBrand {
5578 data: [CpuIdResult; 3],
5579}
5580
5581impl SoCVendorBrand {
5582 pub fn as_str(&self) -> &str {
5584 let brand_string_start = self as *const SoCVendorBrand as *const u8;
5585 let slice = unsafe {
5586 slice::from_raw_parts(brand_string_start, size_of::<SoCVendorBrand>())
5588 };
5589 str::from_utf8(slice).unwrap_or("InvalidSoCVendorString")
5590 }
5591
5592 #[deprecated(
5593 since = "10.0.0",
5594 note = "Use idiomatic function name `as_str` instead"
5595 )]
5596 pub fn as_string(&self) -> &str {
5597 self.as_str()
5598 }
5599}
5600
5601impl fmt::Display for SoCVendorBrand {
5602 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
5603 write!(f, "{}", self.as_str())
5604 }
5605}
5606
5607pub struct HypervisorInfo<R: CpuIdReader> {
5612 read: R,
5613 res: CpuIdResult,
5614}
5615
5616impl<R: CpuIdReader> fmt::Debug for HypervisorInfo<R> {
5617 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
5618 f.debug_struct("HypervisorInfo")
5619 .field("identify", &self.identify())
5620 .field("tsc_frequency", &self.tsc_frequency())
5621 .field("apic_frequency", &self.apic_frequency())
5622 .finish()
5623 }
5624}
5625
5626#[derive(Debug, Eq, PartialEq)]
5628pub enum Hypervisor {
5629 Xen,
5630 VMware,
5631 HyperV,
5632 KVM,
5633 QEMU,
5636 Bhyve,
5637 QNX,
5638 ACRN,
5639 Unknown(u32, u32, u32),
5640}
5641
5642impl<R: CpuIdReader> HypervisorInfo<R> {
5643 pub fn identify(&self) -> Hypervisor {
5654 match (self.res.ebx, self.res.ecx, self.res.edx) {
5655 (0x61774d56, 0x4d566572, 0x65726177) => Hypervisor::VMware,
5657 (0x566e6558, 0x65584d4d, 0x4d4d566e) => Hypervisor::Xen,
5659 (0x7263694d, 0x666f736f, 0x76482074) => Hypervisor::HyperV,
5661 (0x4b4d564b, 0x564b4d56, 0x0000004d) => Hypervisor::KVM,
5663 (0x54474354, 0x43544743, 0x47435447) => Hypervisor::QEMU,
5666 (0x76796862, 0x68622065, 0x20657679) => Hypervisor::Bhyve,
5669 (0x56794842, 0x48422045, 0x20455679) => Hypervisor::Bhyve,
5673 (0x51584e51, 0x53424d56, 0x00004751) => Hypervisor::QNX,
5677 (0x4e524341, 0x4e524341, 0x4e524341) => Hypervisor::ACRN,
5679 (ebx, ecx, edx) => Hypervisor::Unknown(ebx, ecx, edx),
5680 }
5681 }
5682
5683 pub fn tsc_frequency(&self) -> Option<u32> {
5685 if self.res.eax >= 0x40000010 {
5688 let virt_tinfo = self.read.cpuid2(0x40000010, 0);
5689 Some(virt_tinfo.eax)
5690 } else {
5691 None
5692 }
5693 }
5694
5695 pub fn apic_frequency(&self) -> Option<u32> {
5697 if self.res.eax >= 0x40000010 {
5699 let virt_tinfo = self.read.cpuid2(0x40000010, 0);
5700 Some(virt_tinfo.ebx)
5701 } else {
5702 None
5703 }
5704 }
5705}
5706
5707#[cfg(doctest)]
5708mod test_readme {
5709 macro_rules! external_doc_test {
5710 ($x:expr) => {
5711 #[doc = $x]
5712 extern "C" {}
5713 };
5714 }
5715
5716 external_doc_test!(include_str!("../README.md"));
5717}