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 let res1 = self.read.cpuid2(EAX_STRUCTURED_EXTENDED_FEATURE_INFO, 1);
515 Some(ExtendedFeatures {
516 _eax: res.eax,
517 ebx: ExtendedFeaturesEbx::from_bits_truncate(res.ebx),
518 ecx: ExtendedFeaturesEcx::from_bits_truncate(res.ecx),
519 edx: ExtendedFeaturesEdx::from_bits_truncate(res.edx),
520 eax1: ExtendedFeaturesEax1::from_bits_truncate(res1.eax),
521 _ebx1: res1.ebx,
522 _ecx1: res1.ecx,
523 edx1: ExtendedFeaturesEdx1::from_bits_truncate(res1.edx),
524 })
525 } else {
526 None
527 }
528 }
529
530 pub fn get_direct_cache_access_info(&self) -> Option<DirectCacheAccessInfo> {
535 if self.leaf_is_supported(EAX_DIRECT_CACHE_ACCESS_INFO) {
536 let res = self.read.cpuid1(EAX_DIRECT_CACHE_ACCESS_INFO);
537 Some(DirectCacheAccessInfo { eax: res.eax })
538 } else {
539 None
540 }
541 }
542
543 pub fn get_performance_monitoring_info(&self) -> Option<PerformanceMonitoringInfo> {
548 if self.leaf_is_supported(EAX_PERFORMANCE_MONITOR_INFO) {
549 let res = self.read.cpuid1(EAX_PERFORMANCE_MONITOR_INFO);
550 Some(PerformanceMonitoringInfo {
551 eax: res.eax,
552 ebx: PerformanceMonitoringFeaturesEbx::from_bits_truncate(res.ebx),
553 _ecx: res.ecx,
554 edx: res.edx,
555 })
556 } else {
557 None
558 }
559 }
560
561 pub fn get_extended_topology_info(&self) -> Option<ExtendedTopologyIter<R>> {
570 if self.leaf_is_supported(EAX_EXTENDED_TOPOLOGY_INFO) {
571 Some(ExtendedTopologyIter {
572 read: self.read.clone(),
573 level: 0,
574 is_v2: false,
575 })
576 } else {
577 None
578 }
579 }
580
581 pub fn get_extended_topology_info_v2(&self) -> Option<ExtendedTopologyIter<R>> {
586 if self.leaf_is_supported(EAX_EXTENDED_TOPOLOGY_INFO_V2) {
587 Some(ExtendedTopologyIter {
588 read: self.read.clone(),
589 level: 0,
590 is_v2: true,
591 })
592 } else {
593 None
594 }
595 }
596
597 pub fn get_extended_state_info(&self) -> Option<ExtendedStateInfo<R>> {
602 if self.leaf_is_supported(EAX_EXTENDED_STATE_INFO) {
603 let res = self.read.cpuid2(EAX_EXTENDED_STATE_INFO, 0);
604 let res1 = self.read.cpuid2(EAX_EXTENDED_STATE_INFO, 1);
605 Some(ExtendedStateInfo {
606 read: self.read.clone(),
607 eax: ExtendedStateInfoXCR0Flags::from_bits_truncate(res.eax),
608 ebx: res.ebx,
609 ecx: res.ecx,
610 _edx: res.edx,
611 eax1: res1.eax,
612 ebx1: res1.ebx,
613 ecx1: ExtendedStateInfoXSSFlags::from_bits_truncate(res1.ecx),
614 _edx1: res1.edx,
615 })
616 } else {
617 None
618 }
619 }
620
621 pub fn get_rdt_monitoring_info(&self) -> Option<RdtMonitoringInfo<R>> {
626 let res = self.read.cpuid1(EAX_RDT_MONITORING);
627
628 if self.leaf_is_supported(EAX_RDT_MONITORING) {
629 Some(RdtMonitoringInfo {
630 read: self.read.clone(),
631 ebx: res.ebx,
632 edx: res.edx,
633 })
634 } else {
635 None
636 }
637 }
638
639 pub fn get_rdt_allocation_info(&self) -> Option<RdtAllocationInfo<R>> {
644 let res = self.read.cpuid1(EAX_RDT_ALLOCATION);
645
646 if self.leaf_is_supported(EAX_RDT_ALLOCATION) {
647 Some(RdtAllocationInfo {
648 read: self.read.clone(),
649 ebx: res.ebx,
650 })
651 } else {
652 None
653 }
654 }
655
656 pub fn get_sgx_info(&self) -> Option<SgxInfo<R>> {
661 self.get_extended_feature_info().and_then(|info| {
663 if self.leaf_is_supported(EAX_SGX) && info.has_sgx() {
664 let res = self.read.cpuid2(EAX_SGX, 0);
665 let res1 = self.read.cpuid2(EAX_SGX, 1);
666 Some(SgxInfo {
667 read: self.read.clone(),
668 eax: res.eax,
669 ebx: res.ebx,
670 _ecx: res.ecx,
671 edx: res.edx,
672 eax1: res1.eax,
673 ebx1: res1.ebx,
674 ecx1: res1.ecx,
675 edx1: res1.edx,
676 })
677 } else {
678 None
679 }
680 })
681 }
682
683 pub fn get_processor_trace_info(&self) -> Option<ProcessorTraceInfo> {
688 if self.leaf_is_supported(EAX_TRACE_INFO) {
689 let res = self.read.cpuid2(EAX_TRACE_INFO, 0);
690 let res1 = if res.eax >= 1 {
691 Some(self.read.cpuid2(EAX_TRACE_INFO, 1))
692 } else {
693 None
694 };
695
696 Some(ProcessorTraceInfo {
697 _eax: res.eax,
698 ebx: res.ebx,
699 ecx: res.ecx,
700 _edx: res.edx,
701 leaf1: res1,
702 })
703 } else {
704 None
705 }
706 }
707
708 pub fn get_tsc_info(&self) -> Option<TscInfo> {
713 if self.leaf_is_supported(EAX_TIME_STAMP_COUNTER_INFO) {
714 let res = self.read.cpuid2(EAX_TIME_STAMP_COUNTER_INFO, 0);
715 Some(TscInfo {
716 eax: res.eax,
717 ebx: res.ebx,
718 ecx: res.ecx,
719 })
720 } else {
721 None
722 }
723 }
724
725 pub fn get_processor_frequency_info(&self) -> Option<ProcessorFrequencyInfo> {
730 if self.leaf_is_supported(EAX_FREQUENCY_INFO) {
731 let res = self.read.cpuid1(EAX_FREQUENCY_INFO);
732 Some(ProcessorFrequencyInfo {
733 eax: res.eax,
734 ebx: res.ebx,
735 ecx: res.ecx,
736 })
737 } else {
738 None
739 }
740 }
741
742 pub fn get_soc_vendor_info(&self) -> Option<SoCVendorInfo<R>> {
747 if self.leaf_is_supported(EAX_SOC_VENDOR_INFO) {
748 let res = self.read.cpuid1(EAX_SOC_VENDOR_INFO);
749 Some(SoCVendorInfo {
750 read: self.read.clone(),
751 eax: res.eax,
752 ebx: res.ebx,
753 ecx: res.ecx,
754 edx: res.edx,
755 })
756 } else {
757 None
758 }
759 }
760
761 pub fn get_deterministic_address_translation_info(&self) -> Option<DatIter<R>> {
766 if self.leaf_is_supported(EAX_DETERMINISTIC_ADDRESS_TRANSLATION_INFO) {
767 let res = self
768 .read
769 .cpuid2(EAX_DETERMINISTIC_ADDRESS_TRANSLATION_INFO, 0);
770 Some(DatIter {
771 read: self.read.clone(),
772 current: 0,
773 count: res.eax,
774 })
775 } else {
776 None
777 }
778 }
779
780 pub fn get_hypervisor_info(&self) -> Option<HypervisorInfo<R>> {
786 self.get_feature_info()
789 .filter(|fi| fi.has_hypervisor())
790 .and_then(|_| {
791 let res = self.read.cpuid1(EAX_HYPERVISOR_INFO);
792 if res.eax > 0 {
793 Some(HypervisorInfo {
794 read: self.read.clone(),
795 res,
796 })
797 } else {
798 None
799 }
800 })
801 }
802
803 pub fn get_extended_processor_and_feature_identifiers(
808 &self,
809 ) -> Option<ExtendedProcessorFeatureIdentifiers> {
810 if self.leaf_is_supported(EAX_EXTENDED_PROCESSOR_AND_FEATURE_IDENTIFIERS) {
811 Some(ExtendedProcessorFeatureIdentifiers::new(
812 self.vendor,
813 self.read
814 .cpuid1(EAX_EXTENDED_PROCESSOR_AND_FEATURE_IDENTIFIERS),
815 ))
816 } else {
817 None
818 }
819 }
820
821 pub fn get_processor_brand_string(&self) -> Option<ProcessorBrandString> {
826 if self.leaf_is_supported(EAX_EXTENDED_BRAND_STRING)
827 && self.leaf_is_supported(EAX_EXTENDED_BRAND_STRING + 1)
828 && self.leaf_is_supported(EAX_EXTENDED_BRAND_STRING + 2)
829 {
830 Some(ProcessorBrandString::new([
831 self.read.cpuid1(EAX_EXTENDED_BRAND_STRING),
832 self.read.cpuid1(EAX_EXTENDED_BRAND_STRING + 1),
833 self.read.cpuid1(EAX_EXTENDED_BRAND_STRING + 2),
834 ]))
835 } else {
836 None
837 }
838 }
839
840 pub fn get_l1_cache_and_tlb_info(&self) -> Option<L1CacheTlbInfo> {
845 if self.vendor == Vendor::Amd && self.leaf_is_supported(EAX_L1_CACHE_INFO) {
846 Some(L1CacheTlbInfo::new(self.read.cpuid1(EAX_L1_CACHE_INFO)))
847 } else {
848 None
849 }
850 }
851
852 pub fn get_l2_l3_cache_and_tlb_info(&self) -> Option<L2And3CacheTlbInfo> {
857 if self.leaf_is_supported(EAX_L2_L3_CACHE_INFO) {
858 Some(L2And3CacheTlbInfo::new(
859 self.read.cpuid1(EAX_L2_L3_CACHE_INFO),
860 ))
861 } else {
862 None
863 }
864 }
865
866 pub fn get_advanced_power_mgmt_info(&self) -> Option<ApmInfo> {
871 if self.leaf_is_supported(EAX_ADVANCED_POWER_MGMT_INFO) {
872 Some(ApmInfo::new(self.read.cpuid1(EAX_ADVANCED_POWER_MGMT_INFO)))
873 } else {
874 None
875 }
876 }
877
878 pub fn get_processor_capacity_feature_info(&self) -> Option<ProcessorCapacityAndFeatureInfo> {
883 if self.leaf_is_supported(EAX_PROCESSOR_CAPACITY_INFO) {
884 Some(ProcessorCapacityAndFeatureInfo::new(
885 self.read.cpuid1(EAX_PROCESSOR_CAPACITY_INFO),
886 ))
887 } else {
888 None
889 }
890 }
891
892 pub fn get_svm_info(&self) -> Option<SvmFeatures> {
901 let has_svm = self
902 .get_extended_processor_and_feature_identifiers()
903 .map_or(false, |f| f.has_svm());
904 if has_svm && self.leaf_is_supported(EAX_SVM_FEATURES) {
905 Some(SvmFeatures::new(self.read.cpuid1(EAX_SVM_FEATURES)))
906 } else {
907 None
908 }
909 }
910
911 pub fn get_tlb_1gb_page_info(&self) -> Option<Tlb1gbPageInfo> {
916 if self.leaf_is_supported(EAX_TLB_1GB_PAGE_INFO) {
917 Some(Tlb1gbPageInfo::new(self.read.cpuid1(EAX_TLB_1GB_PAGE_INFO)))
918 } else {
919 None
920 }
921 }
922
923 pub fn get_performance_optimization_info(&self) -> Option<PerformanceOptimizationInfo> {
928 if self.leaf_is_supported(EAX_PERFORMANCE_OPTIMIZATION_INFO) {
929 Some(PerformanceOptimizationInfo::new(
930 self.read.cpuid1(EAX_PERFORMANCE_OPTIMIZATION_INFO),
931 ))
932 } else {
933 None
934 }
935 }
936
937 pub fn get_processor_topology_info(&self) -> Option<ProcessorTopologyInfo> {
942 if self.leaf_is_supported(EAX_PROCESSOR_TOPOLOGY_INFO) {
943 Some(ProcessorTopologyInfo::new(
944 self.read.cpuid1(EAX_PROCESSOR_TOPOLOGY_INFO),
945 ))
946 } else {
947 None
948 }
949 }
950
951 pub fn get_memory_encryption_info(&self) -> Option<MemoryEncryptionInfo> {
956 if self.leaf_is_supported(EAX_MEMORY_ENCRYPTION_INFO) {
957 Some(MemoryEncryptionInfo::new(
958 self.read.cpuid1(EAX_MEMORY_ENCRYPTION_INFO),
959 ))
960 } else {
961 None
962 }
963 }
964}
965
966impl<R: CpuIdReader> Debug for CpuId<R> {
967 fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
968 f.debug_struct("CpuId")
969 .field("vendor", &self.vendor)
970 .field("vendor_info", &self.get_vendor_info())
973 .field("feature_info", &self.get_feature_info())
974 .field("cache_info", &self.get_cache_info())
975 .field("processor_serial", &self.get_processor_serial())
976 .field("cache_parameters", &self.get_cache_parameters())
977 .field("monitor_mwait_info", &self.get_monitor_mwait_info())
978 .field("thermal_power_info", &self.get_thermal_power_info())
979 .field("extended_feature_info", &self.get_extended_feature_info())
980 .field(
981 "direct_cache_access_info",
982 &self.get_direct_cache_access_info(),
983 )
984 .field(
985 "performance_monitoring_info",
986 &self.get_performance_monitoring_info(),
987 )
988 .field("extended_topology_info", &self.get_extended_topology_info())
989 .field("extended_state_info", &self.get_extended_state_info())
990 .field("rdt_monitoring_info", &self.get_rdt_monitoring_info())
991 .field("rdt_allocation_info", &self.get_rdt_allocation_info())
992 .field("sgx_info", &self.get_sgx_info())
993 .field("processor_trace_info", &self.get_processor_trace_info())
994 .field("tsc_info", &self.get_tsc_info())
995 .field(
996 "processor_frequency_info",
997 &self.get_processor_frequency_info(),
998 )
999 .field(
1000 "deterministic_address_translation_info",
1001 &self.get_deterministic_address_translation_info(),
1002 )
1003 .field("soc_vendor_info", &self.get_soc_vendor_info())
1004 .field("hypervisor_info", &self.get_hypervisor_info())
1005 .field(
1006 "extended_processor_and_feature_identifiers",
1007 &self.get_extended_processor_and_feature_identifiers(),
1008 )
1009 .field("processor_brand_string", &self.get_processor_brand_string())
1010 .field("l1_cache_and_tlb_info", &self.get_l1_cache_and_tlb_info())
1011 .field(
1012 "l2_l3_cache_and_tlb_info",
1013 &self.get_l2_l3_cache_and_tlb_info(),
1014 )
1015 .field(
1016 "advanced_power_mgmt_info",
1017 &self.get_advanced_power_mgmt_info(),
1018 )
1019 .field(
1020 "processor_capacity_feature_info",
1021 &self.get_processor_capacity_feature_info(),
1022 )
1023 .field("svm_info", &self.get_svm_info())
1024 .field("tlb_1gb_page_info", &self.get_tlb_1gb_page_info())
1025 .field(
1026 "performance_optimization_info",
1027 &self.get_performance_optimization_info(),
1028 )
1029 .field(
1030 "processor_topology_info",
1031 &self.get_processor_topology_info(),
1032 )
1033 .field("memory_encryption_info", &self.get_memory_encryption_info())
1034 .finish()
1035 }
1036}
1037
1038#[derive(PartialEq, Eq)]
1050#[repr(C)]
1051pub struct VendorInfo {
1052 ebx: u32,
1053 edx: u32,
1054 ecx: u32,
1055}
1056
1057impl VendorInfo {
1058 pub fn as_str(&self) -> &str {
1060 let brand_string_start = self as *const VendorInfo as *const u8;
1061 let slice = unsafe {
1062 slice::from_raw_parts(brand_string_start, size_of::<VendorInfo>())
1065 };
1066
1067 str::from_utf8(slice).unwrap_or("InvalidVendorString")
1068 }
1069
1070 #[deprecated(
1071 since = "10.0.0",
1072 note = "Use idiomatic function name `as_str` instead"
1073 )]
1074 pub fn as_string(&self) -> &str {
1075 self.as_str()
1076 }
1077}
1078
1079impl Debug for VendorInfo {
1080 fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
1081 f.debug_struct("VendorInfo")
1082 .field("brand_string", &self.as_str())
1083 .finish()
1084 }
1085}
1086
1087impl fmt::Display for VendorInfo {
1088 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1089 write!(f, "{}", self.as_str())
1090 }
1091}
1092
1093#[derive(PartialEq, Eq, Clone)]
1101pub struct CacheInfoIter {
1102 current: u32,
1103 eax: u32,
1104 ebx: u32,
1105 ecx: u32,
1106 edx: u32,
1107}
1108
1109impl Iterator for CacheInfoIter {
1110 type Item = CacheInfo;
1111
1112 fn next(&mut self) -> Option<CacheInfo> {
1114 if self.current >= 4 * 4 {
1118 return None;
1119 }
1120 let reg_index = self.current % 4;
1121 let byte_index = self.current / 4;
1122
1123 let reg = match reg_index {
1124 0 => self.eax,
1125 1 => self.ebx,
1126 2 => self.ecx,
1127 3 => self.edx,
1128 _ => unreachable!(),
1129 };
1130
1131 let byte = match byte_index {
1132 0 => reg,
1133 1 => reg >> 8,
1134 2 => reg >> 16,
1135 3 => reg >> 24,
1136 _ => unreachable!(),
1137 } as u8;
1138
1139 if byte == 0 {
1140 self.current += 1;
1141 return self.next();
1142 }
1143
1144 for cache_info in CACHE_INFO_TABLE.iter() {
1145 if cache_info.num == byte {
1146 self.current += 1;
1147 return Some(*cache_info);
1148 }
1149 }
1150
1151 None
1152 }
1153}
1154
1155impl Debug for CacheInfoIter {
1156 fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
1157 let mut debug = f.debug_list();
1158 self.clone().for_each(|ref item| {
1159 debug.entry(item);
1160 });
1161 debug.finish()
1162 }
1163}
1164
1165#[derive(Copy, Clone, Debug)]
1167pub enum CacheInfoType {
1168 General,
1169 Cache,
1170 TLB,
1171 STLB,
1172 DTLB,
1173 Prefetch,
1174}
1175
1176#[derive(Copy, Clone)]
1178pub struct CacheInfo {
1179 pub num: u8,
1181 pub typ: CacheInfoType,
1183}
1184
1185impl CacheInfo {
1186 pub fn desc(&self) -> &'static str {
1188 match self.num {
1189 0x00 => "Null descriptor, this byte contains no information",
1190 0x01 => "Instruction TLB: 4 KByte pages, 4-way set associative, 32 entries",
1191 0x02 => "Instruction TLB: 4 MByte pages, fully associative, 2 entries",
1192 0x03 => "Data TLB: 4 KByte pages, 4-way set associative, 64 entries",
1193 0x04 => "Data TLB: 4 MByte pages, 4-way set associative, 8 entries",
1194 0x05 => "Data TLB1: 4 MByte pages, 4-way set associative, 32 entries",
1195 0x06 => "1st-level instruction cache: 8 KBytes, 4-way set associative, 32 byte line size",
1196 0x08 => "1st-level instruction cache: 16 KBytes, 4-way set associative, 32 byte line size",
1197 0x09 => "1st-level instruction cache: 32KBytes, 4-way set associative, 64 byte line size",
1198 0x0A => "1st-level data cache: 8 KBytes, 2-way set associative, 32 byte line size",
1199 0x0B => "Instruction TLB: 4 MByte pages, 4-way set associative, 4 entries",
1200 0x0C => "1st-level data cache: 16 KBytes, 4-way set associative, 32 byte line size",
1201 0x0D => "1st-level data cache: 16 KBytes, 4-way set associative, 64 byte line size",
1202 0x0E => "1st-level data cache: 24 KBytes, 6-way set associative, 64 byte line size",
1203 0x1D => "2nd-level cache: 128 KBytes, 2-way set associative, 64 byte line size",
1204 0x21 => "2nd-level cache: 256 KBytes, 8-way set associative, 64 byte line size",
1205 0x22 => "3rd-level cache: 512 KBytes, 4-way set associative, 64 byte line size, 2 lines per sector",
1206 0x23 => "3rd-level cache: 1 MBytes, 8-way set associative, 64 byte line size, 2 lines per sector",
1207 0x24 => "2nd-level cache: 1 MBytes, 16-way set associative, 64 byte line size",
1208 0x25 => "3rd-level cache: 2 MBytes, 8-way set associative, 64 byte line size, 2 lines per sector",
1209 0x29 => "3rd-level cache: 4 MBytes, 8-way set associative, 64 byte line size, 2 lines per sector",
1210 0x2C => "1st-level data cache: 32 KBytes, 8-way set associative, 64 byte line size",
1211 0x30 => "1st-level instruction cache: 32 KBytes, 8-way set associative, 64 byte line size",
1212 0x40 => "No 2nd-level cache or, if processor contains a valid 2nd-level cache, no 3rd-level cache",
1213 0x41 => "2nd-level cache: 128 KBytes, 4-way set associative, 32 byte line size",
1214 0x42 => "2nd-level cache: 256 KBytes, 4-way set associative, 32 byte line size",
1215 0x43 => "2nd-level cache: 512 KBytes, 4-way set associative, 32 byte line size",
1216 0x44 => "2nd-level cache: 1 MByte, 4-way set associative, 32 byte line size",
1217 0x45 => "2nd-level cache: 2 MByte, 4-way set associative, 32 byte line size",
1218 0x46 => "3rd-level cache: 4 MByte, 4-way set associative, 64 byte line size",
1219 0x47 => "3rd-level cache: 8 MByte, 8-way set associative, 64 byte line size",
1220 0x48 => "2nd-level cache: 3MByte, 12-way set associative, 64 byte line size",
1221 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",
1222 0x4A => "3rd-level cache: 6MByte, 12-way set associative, 64 byte line size",
1223 0x4B => "3rd-level cache: 8MByte, 16-way set associative, 64 byte line size",
1224 0x4C => "3rd-level cache: 12MByte, 12-way set associative, 64 byte line size",
1225 0x4D => "3rd-level cache: 16MByte, 16-way set associative, 64 byte line size",
1226 0x4E => "2nd-level cache: 6MByte, 24-way set associative, 64 byte line size",
1227 0x4F => "Instruction TLB: 4 KByte pages, 32 entries",
1228 0x50 => "Instruction TLB: 4 KByte and 2-MByte or 4-MByte pages, 64 entries",
1229 0x51 => "Instruction TLB: 4 KByte and 2-MByte or 4-MByte pages, 128 entries",
1230 0x52 => "Instruction TLB: 4 KByte and 2-MByte or 4-MByte pages, 256 entries",
1231 0x55 => "Instruction TLB: 2-MByte or 4-MByte pages, fully associative, 7 entries",
1232 0x56 => "Data TLB0: 4 MByte pages, 4-way set associative, 16 entries",
1233 0x57 => "Data TLB0: 4 KByte pages, 4-way associative, 16 entries",
1234 0x59 => "Data TLB0: 4 KByte pages, fully associative, 16 entries",
1235 0x5A => "Data TLB0: 2-MByte or 4 MByte pages, 4-way set associative, 32 entries",
1236 0x5B => "Data TLB: 4 KByte and 4 MByte pages, 64 entries",
1237 0x5C => "Data TLB: 4 KByte and 4 MByte pages,128 entries",
1238 0x5D => "Data TLB: 4 KByte and 4 MByte pages,256 entries",
1239 0x60 => "1st-level data cache: 16 KByte, 8-way set associative, 64 byte line size",
1240 0x61 => "Instruction TLB: 4 KByte pages, fully associative, 48 entries",
1241 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",
1242 0x64 => "Data TLB: 4 KByte pages, 4-way set associative, 512 entries",
1243 0x66 => "1st-level data cache: 8 KByte, 4-way set associative, 64 byte line size",
1244 0x67 => "1st-level data cache: 16 KByte, 4-way set associative, 64 byte line size",
1245 0x68 => "1st-level data cache: 32 KByte, 4-way set associative, 64 byte line size",
1246 0x6A => "uTLB: 4 KByte pages, 8-way set associative, 64 entries",
1247 0x6B => "DTLB: 4 KByte pages, 8-way set associative, 256 entries",
1248 0x6C => "DTLB: 2M/4M pages, 8-way set associative, 128 entries",
1249 0x6D => "DTLB: 1 GByte pages, fully associative, 16 entries",
1250 0x70 => "Trace cache: 12 K-μop, 8-way set associative",
1251 0x71 => "Trace cache: 16 K-μop, 8-way set associative",
1252 0x72 => "Trace cache: 32 K-μop, 8-way set associative",
1253 0x76 => "Instruction TLB: 2M/4M pages, fully associative, 8 entries",
1254 0x78 => "2nd-level cache: 1 MByte, 4-way set associative, 64byte line size",
1255 0x79 => "2nd-level cache: 128 KByte, 8-way set associative, 64 byte line size, 2 lines per sector",
1256 0x7A => "2nd-level cache: 256 KByte, 8-way set associative, 64 byte line size, 2 lines per sector",
1257 0x7B => "2nd-level cache: 512 KByte, 8-way set associative, 64 byte line size, 2 lines per sector",
1258 0x7C => "2nd-level cache: 1 MByte, 8-way set associative, 64 byte line size, 2 lines per sector",
1259 0x7D => "2nd-level cache: 2 MByte, 8-way set associative, 64byte line size",
1260 0x7F => "2nd-level cache: 512 KByte, 2-way set associative, 64-byte line size",
1261 0x80 => "2nd-level cache: 512 KByte, 8-way set associative, 64-byte line size",
1262 0x82 => "2nd-level cache: 256 KByte, 8-way set associative, 32 byte line size",
1263 0x83 => "2nd-level cache: 512 KByte, 8-way set associative, 32 byte line size",
1264 0x84 => "2nd-level cache: 1 MByte, 8-way set associative, 32 byte line size",
1265 0x85 => "2nd-level cache: 2 MByte, 8-way set associative, 32 byte line size",
1266 0x86 => "2nd-level cache: 512 KByte, 4-way set associative, 64 byte line size",
1267 0x87 => "2nd-level cache: 1 MByte, 8-way set associative, 64 byte line size",
1268 0xA0 => "DTLB: 4k pages, fully associative, 32 entries",
1269 0xB0 => "Instruction TLB: 4 KByte pages, 4-way set associative, 128 entries",
1270 0xB1 => "Instruction TLB: 2M pages, 4-way, 8 entries or 4M pages, 4-way, 4 entries",
1271 0xB2 => "Instruction TLB: 4KByte pages, 4-way set associative, 64 entries",
1272 0xB3 => "Data TLB: 4 KByte pages, 4-way set associative, 128 entries",
1273 0xB4 => "Data TLB1: 4 KByte pages, 4-way associative, 256 entries",
1274 0xB5 => "Instruction TLB: 4KByte pages, 8-way set associative, 64 entries",
1275 0xB6 => "Instruction TLB: 4KByte pages, 8-way set associative, 128 entries",
1276 0xBA => "Data TLB1: 4 KByte pages, 4-way associative, 64 entries",
1277 0xC0 => "Data TLB: 4 KByte and 4 MByte pages, 4-way associative, 8 entries",
1278 0xC1 => "Shared 2nd-Level TLB: 4 KByte/2MByte pages, 8-way associative, 1024 entries",
1279 0xC2 => "DTLB: 2 MByte/$MByte pages, 4-way associative, 16 entries",
1280 0xC3 => "Shared 2nd-Level TLB: 4 KByte /2 MByte pages, 6-way associative, 1536 entries. Also 1GBbyte pages, 4-way, 16 entries.",
1281 0xC4 => "DTLB: 2M/4M Byte pages, 4-way associative, 32 entries",
1282 0xCA => "Shared 2nd-Level TLB: 4 KByte pages, 4-way associative, 512 entries",
1283 0xD0 => "3rd-level cache: 512 KByte, 4-way set associative, 64 byte line size",
1284 0xD1 => "3rd-level cache: 1 MByte, 4-way set associative, 64 byte line size",
1285 0xD2 => "3rd-level cache: 2 MByte, 4-way set associative, 64 byte line size",
1286 0xD6 => "3rd-level cache: 1 MByte, 8-way set associative, 64 byte line size",
1287 0xD7 => "3rd-level cache: 2 MByte, 8-way set associative, 64 byte line size",
1288 0xD8 => "3rd-level cache: 4 MByte, 8-way set associative, 64 byte line size",
1289 0xDC => "3rd-level cache: 1.5 MByte, 12-way set associative, 64 byte line size",
1290 0xDD => "3rd-level cache: 3 MByte, 12-way set associative, 64 byte line size",
1291 0xDE => "3rd-level cache: 6 MByte, 12-way set associative, 64 byte line size",
1292 0xE2 => "3rd-level cache: 2 MByte, 16-way set associative, 64 byte line size",
1293 0xE3 => "3rd-level cache: 4 MByte, 16-way set associative, 64 byte line size",
1294 0xE4 => "3rd-level cache: 8 MByte, 16-way set associative, 64 byte line size",
1295 0xEA => "3rd-level cache: 12MByte, 24-way set associative, 64 byte line size",
1296 0xEB => "3rd-level cache: 18MByte, 24-way set associative, 64 byte line size",
1297 0xEC => "3rd-level cache: 24MByte, 24-way set associative, 64 byte line size",
1298 0xF0 => "64-Byte prefetching",
1299 0xF1 => "128-Byte prefetching",
1300 0xFE => "CPUID leaf 2 does not report TLB descriptor information; use CPUID leaf 18H to query TLB and other address translation parameters.",
1301 0xFF => "CPUID leaf 2 does not report cache descriptor information, use CPUID leaf 4 to query cache parameters",
1302 _ => "Unknown cache type!"
1303 }
1304 }
1305}
1306
1307impl Debug for CacheInfo {
1308 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
1309 f.debug_struct("CacheInfo")
1310 .field("typ", &self.typ)
1311 .field("desc", &self.desc())
1312 .finish()
1313 }
1314}
1315
1316impl fmt::Display for CacheInfo {
1317 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1318 let typ = match self.typ {
1319 CacheInfoType::General => "N/A",
1320 CacheInfoType::Cache => "Cache",
1321 CacheInfoType::TLB => "TLB",
1322 CacheInfoType::STLB => "STLB",
1323 CacheInfoType::DTLB => "DTLB",
1324 CacheInfoType::Prefetch => "Prefetcher",
1325 };
1326
1327 write!(f, "{:x}:\t {}: {}", self.num, typ, self.desc())
1328 }
1329}
1330
1331pub const CACHE_INFO_TABLE: [CacheInfo; 108] = [
1333 CacheInfo {
1334 num: 0x00,
1335 typ: CacheInfoType::General,
1336 },
1337 CacheInfo {
1338 num: 0x01,
1339 typ: CacheInfoType::TLB,
1340 },
1341 CacheInfo {
1342 num: 0x02,
1343 typ: CacheInfoType::TLB,
1344 },
1345 CacheInfo {
1346 num: 0x03,
1347 typ: CacheInfoType::TLB,
1348 },
1349 CacheInfo {
1350 num: 0x04,
1351 typ: CacheInfoType::TLB,
1352 },
1353 CacheInfo {
1354 num: 0x05,
1355 typ: CacheInfoType::TLB,
1356 },
1357 CacheInfo {
1358 num: 0x06,
1359 typ: CacheInfoType::Cache,
1360 },
1361 CacheInfo {
1362 num: 0x08,
1363 typ: CacheInfoType::Cache,
1364 },
1365 CacheInfo {
1366 num: 0x09,
1367 typ: CacheInfoType::Cache,
1368 },
1369 CacheInfo {
1370 num: 0x0A,
1371 typ: CacheInfoType::Cache,
1372 },
1373 CacheInfo {
1374 num: 0x0B,
1375 typ: CacheInfoType::TLB,
1376 },
1377 CacheInfo {
1378 num: 0x0C,
1379 typ: CacheInfoType::Cache,
1380 },
1381 CacheInfo {
1382 num: 0x0D,
1383 typ: CacheInfoType::Cache,
1384 },
1385 CacheInfo {
1386 num: 0x0E,
1387 typ: CacheInfoType::Cache,
1388 },
1389 CacheInfo {
1390 num: 0x21,
1391 typ: CacheInfoType::Cache,
1392 },
1393 CacheInfo {
1394 num: 0x22,
1395 typ: CacheInfoType::Cache,
1396 },
1397 CacheInfo {
1398 num: 0x23,
1399 typ: CacheInfoType::Cache,
1400 },
1401 CacheInfo {
1402 num: 0x24,
1403 typ: CacheInfoType::Cache,
1404 },
1405 CacheInfo {
1406 num: 0x25,
1407 typ: CacheInfoType::Cache,
1408 },
1409 CacheInfo {
1410 num: 0x29,
1411 typ: CacheInfoType::Cache,
1412 },
1413 CacheInfo {
1414 num: 0x2C,
1415 typ: CacheInfoType::Cache,
1416 },
1417 CacheInfo {
1418 num: 0x30,
1419 typ: CacheInfoType::Cache,
1420 },
1421 CacheInfo {
1422 num: 0x40,
1423 typ: CacheInfoType::Cache,
1424 },
1425 CacheInfo {
1426 num: 0x41,
1427 typ: CacheInfoType::Cache,
1428 },
1429 CacheInfo {
1430 num: 0x42,
1431 typ: CacheInfoType::Cache,
1432 },
1433 CacheInfo {
1434 num: 0x43,
1435 typ: CacheInfoType::Cache,
1436 },
1437 CacheInfo {
1438 num: 0x44,
1439 typ: CacheInfoType::Cache,
1440 },
1441 CacheInfo {
1442 num: 0x45,
1443 typ: CacheInfoType::Cache,
1444 },
1445 CacheInfo {
1446 num: 0x46,
1447 typ: CacheInfoType::Cache,
1448 },
1449 CacheInfo {
1450 num: 0x47,
1451 typ: CacheInfoType::Cache,
1452 },
1453 CacheInfo {
1454 num: 0x48,
1455 typ: CacheInfoType::Cache,
1456 },
1457 CacheInfo {
1458 num: 0x49,
1459 typ: CacheInfoType::Cache,
1460 },
1461 CacheInfo {
1462 num: 0x4A,
1463 typ: CacheInfoType::Cache,
1464 },
1465 CacheInfo {
1466 num: 0x4B,
1467 typ: CacheInfoType::Cache,
1468 },
1469 CacheInfo {
1470 num: 0x4C,
1471 typ: CacheInfoType::Cache,
1472 },
1473 CacheInfo {
1474 num: 0x4D,
1475 typ: CacheInfoType::Cache,
1476 },
1477 CacheInfo {
1478 num: 0x4E,
1479 typ: CacheInfoType::Cache,
1480 },
1481 CacheInfo {
1482 num: 0x4F,
1483 typ: CacheInfoType::TLB,
1484 },
1485 CacheInfo {
1486 num: 0x50,
1487 typ: CacheInfoType::TLB,
1488 },
1489 CacheInfo {
1490 num: 0x51,
1491 typ: CacheInfoType::TLB,
1492 },
1493 CacheInfo {
1494 num: 0x52,
1495 typ: CacheInfoType::TLB,
1496 },
1497 CacheInfo {
1498 num: 0x55,
1499 typ: CacheInfoType::TLB,
1500 },
1501 CacheInfo {
1502 num: 0x56,
1503 typ: CacheInfoType::TLB,
1504 },
1505 CacheInfo {
1506 num: 0x57,
1507 typ: CacheInfoType::TLB,
1508 },
1509 CacheInfo {
1510 num: 0x59,
1511 typ: CacheInfoType::TLB,
1512 },
1513 CacheInfo {
1514 num: 0x5A,
1515 typ: CacheInfoType::TLB,
1516 },
1517 CacheInfo {
1518 num: 0x5B,
1519 typ: CacheInfoType::TLB,
1520 },
1521 CacheInfo {
1522 num: 0x5C,
1523 typ: CacheInfoType::TLB,
1524 },
1525 CacheInfo {
1526 num: 0x5D,
1527 typ: CacheInfoType::TLB,
1528 },
1529 CacheInfo {
1530 num: 0x60,
1531 typ: CacheInfoType::Cache,
1532 },
1533 CacheInfo {
1534 num: 0x61,
1535 typ: CacheInfoType::TLB,
1536 },
1537 CacheInfo {
1538 num: 0x63,
1539 typ: CacheInfoType::TLB,
1540 },
1541 CacheInfo {
1542 num: 0x66,
1543 typ: CacheInfoType::Cache,
1544 },
1545 CacheInfo {
1546 num: 0x67,
1547 typ: CacheInfoType::Cache,
1548 },
1549 CacheInfo {
1550 num: 0x68,
1551 typ: CacheInfoType::Cache,
1552 },
1553 CacheInfo {
1554 num: 0x6A,
1555 typ: CacheInfoType::Cache,
1556 },
1557 CacheInfo {
1558 num: 0x6B,
1559 typ: CacheInfoType::Cache,
1560 },
1561 CacheInfo {
1562 num: 0x6C,
1563 typ: CacheInfoType::Cache,
1564 },
1565 CacheInfo {
1566 num: 0x6D,
1567 typ: CacheInfoType::Cache,
1568 },
1569 CacheInfo {
1570 num: 0x70,
1571 typ: CacheInfoType::Cache,
1572 },
1573 CacheInfo {
1574 num: 0x71,
1575 typ: CacheInfoType::Cache,
1576 },
1577 CacheInfo {
1578 num: 0x72,
1579 typ: CacheInfoType::Cache,
1580 },
1581 CacheInfo {
1582 num: 0x76,
1583 typ: CacheInfoType::TLB,
1584 },
1585 CacheInfo {
1586 num: 0x78,
1587 typ: CacheInfoType::Cache,
1588 },
1589 CacheInfo {
1590 num: 0x79,
1591 typ: CacheInfoType::Cache,
1592 },
1593 CacheInfo {
1594 num: 0x7A,
1595 typ: CacheInfoType::Cache,
1596 },
1597 CacheInfo {
1598 num: 0x7B,
1599 typ: CacheInfoType::Cache,
1600 },
1601 CacheInfo {
1602 num: 0x7C,
1603 typ: CacheInfoType::Cache,
1604 },
1605 CacheInfo {
1606 num: 0x7D,
1607 typ: CacheInfoType::Cache,
1608 },
1609 CacheInfo {
1610 num: 0x7F,
1611 typ: CacheInfoType::Cache,
1612 },
1613 CacheInfo {
1614 num: 0x80,
1615 typ: CacheInfoType::Cache,
1616 },
1617 CacheInfo {
1618 num: 0x82,
1619 typ: CacheInfoType::Cache,
1620 },
1621 CacheInfo {
1622 num: 0x83,
1623 typ: CacheInfoType::Cache,
1624 },
1625 CacheInfo {
1626 num: 0x84,
1627 typ: CacheInfoType::Cache,
1628 },
1629 CacheInfo {
1630 num: 0x85,
1631 typ: CacheInfoType::Cache,
1632 },
1633 CacheInfo {
1634 num: 0x86,
1635 typ: CacheInfoType::Cache,
1636 },
1637 CacheInfo {
1638 num: 0x87,
1639 typ: CacheInfoType::Cache,
1640 },
1641 CacheInfo {
1642 num: 0xB0,
1643 typ: CacheInfoType::TLB,
1644 },
1645 CacheInfo {
1646 num: 0xB1,
1647 typ: CacheInfoType::TLB,
1648 },
1649 CacheInfo {
1650 num: 0xB2,
1651 typ: CacheInfoType::TLB,
1652 },
1653 CacheInfo {
1654 num: 0xB3,
1655 typ: CacheInfoType::TLB,
1656 },
1657 CacheInfo {
1658 num: 0xB4,
1659 typ: CacheInfoType::TLB,
1660 },
1661 CacheInfo {
1662 num: 0xB5,
1663 typ: CacheInfoType::TLB,
1664 },
1665 CacheInfo {
1666 num: 0xB6,
1667 typ: CacheInfoType::TLB,
1668 },
1669 CacheInfo {
1670 num: 0xBA,
1671 typ: CacheInfoType::TLB,
1672 },
1673 CacheInfo {
1674 num: 0xC0,
1675 typ: CacheInfoType::TLB,
1676 },
1677 CacheInfo {
1678 num: 0xC1,
1679 typ: CacheInfoType::STLB,
1680 },
1681 CacheInfo {
1682 num: 0xC2,
1683 typ: CacheInfoType::DTLB,
1684 },
1685 CacheInfo {
1686 num: 0xCA,
1687 typ: CacheInfoType::STLB,
1688 },
1689 CacheInfo {
1690 num: 0xD0,
1691 typ: CacheInfoType::Cache,
1692 },
1693 CacheInfo {
1694 num: 0xD1,
1695 typ: CacheInfoType::Cache,
1696 },
1697 CacheInfo {
1698 num: 0xD2,
1699 typ: CacheInfoType::Cache,
1700 },
1701 CacheInfo {
1702 num: 0xD6,
1703 typ: CacheInfoType::Cache,
1704 },
1705 CacheInfo {
1706 num: 0xD7,
1707 typ: CacheInfoType::Cache,
1708 },
1709 CacheInfo {
1710 num: 0xD8,
1711 typ: CacheInfoType::Cache,
1712 },
1713 CacheInfo {
1714 num: 0xDC,
1715 typ: CacheInfoType::Cache,
1716 },
1717 CacheInfo {
1718 num: 0xDD,
1719 typ: CacheInfoType::Cache,
1720 },
1721 CacheInfo {
1722 num: 0xDE,
1723 typ: CacheInfoType::Cache,
1724 },
1725 CacheInfo {
1726 num: 0xE2,
1727 typ: CacheInfoType::Cache,
1728 },
1729 CacheInfo {
1730 num: 0xE3,
1731 typ: CacheInfoType::Cache,
1732 },
1733 CacheInfo {
1734 num: 0xE4,
1735 typ: CacheInfoType::Cache,
1736 },
1737 CacheInfo {
1738 num: 0xEA,
1739 typ: CacheInfoType::Cache,
1740 },
1741 CacheInfo {
1742 num: 0xEB,
1743 typ: CacheInfoType::Cache,
1744 },
1745 CacheInfo {
1746 num: 0xEC,
1747 typ: CacheInfoType::Cache,
1748 },
1749 CacheInfo {
1750 num: 0xF0,
1751 typ: CacheInfoType::Prefetch,
1752 },
1753 CacheInfo {
1754 num: 0xF1,
1755 typ: CacheInfoType::Prefetch,
1756 },
1757 CacheInfo {
1758 num: 0xFE,
1759 typ: CacheInfoType::General,
1760 },
1761 CacheInfo {
1762 num: 0xFF,
1763 typ: CacheInfoType::General,
1764 },
1765];
1766
1767#[derive(PartialEq, Eq)]
1778pub struct ProcessorSerial {
1779 ecx: u32,
1781 edx: u32,
1783 eax: u32,
1785}
1786
1787impl ProcessorSerial {
1788 pub fn serial_lower(&self) -> u32 {
1792 self.ecx
1793 }
1794
1795 pub fn serial_middle(&self) -> u32 {
1799 self.edx
1800 }
1801
1802 pub fn serial_upper(&self) -> u32 {
1804 self.eax
1805 }
1806
1807 pub fn serial(&self) -> u64 {
1809 (self.serial_lower() as u64) | (self.serial_middle() as u64) << 32
1810 }
1811
1812 pub fn serial_all(&self) -> u128 {
1814 (self.serial_lower() as u128)
1815 | ((self.serial_middle() as u128) << 32)
1816 | ((self.serial_upper() as u128) << 64)
1817 }
1818}
1819
1820impl Debug for ProcessorSerial {
1821 fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
1822 f.debug_struct("ProcessorSerial")
1823 .field("serial_lower", &self.serial_lower())
1824 .field("serial_middle", &self.serial_middle())
1825 .finish()
1826 }
1827}
1828
1829pub struct FeatureInfo {
1834 vendor: Vendor,
1835 eax: u32,
1836 ebx: u32,
1837 edx_ecx: FeatureInfoFlags,
1838}
1839
1840impl FeatureInfo {
1841 pub fn extended_family_id(&self) -> u8 {
1843 get_bits(self.eax, 20, 27) as u8
1844 }
1845
1846 pub fn extended_model_id(&self) -> u8 {
1848 get_bits(self.eax, 16, 19) as u8
1849 }
1850
1851 pub fn base_family_id(&self) -> u8 {
1853 get_bits(self.eax, 8, 11) as u8
1854 }
1855
1856 pub fn base_model_id(&self) -> u8 {
1858 get_bits(self.eax, 4, 7) as u8
1859 }
1860
1861 pub fn family_id(&self) -> u8 {
1862 let base_family_id = self.base_family_id();
1863 let extended_family_id = self.extended_family_id();
1864 let just_use_base = (self.vendor == Vendor::Amd && base_family_id < 0xf)
1865 || (self.vendor == Vendor::Intel && base_family_id != 0xf);
1866
1867 if just_use_base {
1868 base_family_id
1869 } else {
1870 base_family_id + extended_family_id
1871 }
1872 }
1873
1874 pub fn model_id(&self) -> u8 {
1875 let base_family_id = self.base_family_id();
1876 let base_model_id = self.base_model_id();
1877 let extended_model_id = self.extended_model_id();
1878 let just_use_base = (self.vendor == Vendor::Amd && base_family_id < 0xf)
1879 || (self.vendor == Vendor::Intel && base_family_id != 0xf && base_family_id != 0x6);
1880
1881 if just_use_base {
1882 base_model_id
1883 } else {
1884 (extended_model_id << 4) | base_model_id
1885 }
1886 }
1887
1888 pub fn stepping_id(&self) -> u8 {
1890 get_bits(self.eax, 0, 3) as u8
1891 }
1892
1893 pub fn brand_index(&self) -> u8 {
1895 get_bits(self.ebx, 0, 7) as u8
1896 }
1897
1898 pub fn cflush_cache_line_size(&self) -> u8 {
1900 get_bits(self.ebx, 8, 15) as u8
1901 }
1902
1903 pub fn initial_local_apic_id(&self) -> u8 {
1905 get_bits(self.ebx, 24, 31) as u8
1906 }
1907
1908 pub fn max_logical_processor_ids(&self) -> u8 {
1910 get_bits(self.ebx, 16, 23) as u8
1911 }
1912
1913 check_flag!(
1914 doc = "Streaming SIMD Extensions 3 (SSE3). A value of 1 indicates the processor \
1915 supports this technology.",
1916 has_sse3,
1917 edx_ecx,
1918 FeatureInfoFlags::SSE3
1919 );
1920
1921 check_flag!(
1922 doc = "PCLMULQDQ. A value of 1 indicates the processor supports the PCLMULQDQ \
1923 instruction",
1924 has_pclmulqdq,
1925 edx_ecx,
1926 FeatureInfoFlags::PCLMULQDQ
1927 );
1928
1929 check_flag!(
1930 doc = "64-bit DS Area. A value of 1 indicates the processor supports DS area \
1931 using 64-bit layout",
1932 has_ds_area,
1933 edx_ecx,
1934 FeatureInfoFlags::DTES64
1935 );
1936
1937 check_flag!(
1938 doc = "MONITOR/MWAIT. A value of 1 indicates the processor supports this feature.",
1939 has_monitor_mwait,
1940 edx_ecx,
1941 FeatureInfoFlags::MONITOR
1942 );
1943
1944 check_flag!(
1945 doc = "CPL Qualified Debug Store. A value of 1 indicates the processor supports \
1946 the extensions to the Debug Store feature to allow for branch message \
1947 storage qualified by CPL.",
1948 has_cpl,
1949 edx_ecx,
1950 FeatureInfoFlags::DSCPL
1951 );
1952
1953 check_flag!(
1954 doc = "Virtual Machine Extensions. A value of 1 indicates that the processor \
1955 supports this technology.",
1956 has_vmx,
1957 edx_ecx,
1958 FeatureInfoFlags::VMX
1959 );
1960
1961 check_flag!(
1962 doc = "Safer Mode Extensions. A value of 1 indicates that the processor supports \
1963 this technology. See Chapter 5, Safer Mode Extensions Reference.",
1964 has_smx,
1965 edx_ecx,
1966 FeatureInfoFlags::SMX
1967 );
1968
1969 check_flag!(
1970 doc = "Enhanced Intel SpeedStep® technology. A value of 1 indicates that the \
1971 processor supports this technology.",
1972 has_eist,
1973 edx_ecx,
1974 FeatureInfoFlags::EIST
1975 );
1976
1977 check_flag!(
1978 doc = "Thermal Monitor 2. A value of 1 indicates whether the processor supports \
1979 this technology.",
1980 has_tm2,
1981 edx_ecx,
1982 FeatureInfoFlags::TM2
1983 );
1984
1985 check_flag!(
1986 doc = "A value of 1 indicates the presence of the Supplemental Streaming SIMD \
1987 Extensions 3 (SSSE3). A value of 0 indicates the instruction extensions \
1988 are not present in the processor",
1989 has_ssse3,
1990 edx_ecx,
1991 FeatureInfoFlags::SSSE3
1992 );
1993
1994 check_flag!(
1995 doc = "L1 Context ID. A value of 1 indicates the L1 data cache mode can be set \
1996 to either adaptive mode or shared mode. A value of 0 indicates this \
1997 feature is not supported. See definition of the IA32_MISC_ENABLE MSR Bit \
1998 24 (L1 Data Cache Context Mode) for details.",
1999 has_cnxtid,
2000 edx_ecx,
2001 FeatureInfoFlags::CNXTID
2002 );
2003
2004 check_flag!(
2005 doc = "A value of 1 indicates the processor supports FMA extensions using YMM \
2006 state.",
2007 has_fma,
2008 edx_ecx,
2009 FeatureInfoFlags::FMA
2010 );
2011
2012 check_flag!(
2013 doc = "CMPXCHG16B Available. A value of 1 indicates that the feature is \
2014 available. See the CMPXCHG8B/CMPXCHG16B Compare and Exchange Bytes \
2015 section. 14",
2016 has_cmpxchg16b,
2017 edx_ecx,
2018 FeatureInfoFlags::CMPXCHG16B
2019 );
2020
2021 check_flag!(
2022 doc = "Perfmon and Debug Capability: A value of 1 indicates the processor \
2023 supports the performance and debug feature indication MSR \
2024 IA32_PERF_CAPABILITIES.",
2025 has_pdcm,
2026 edx_ecx,
2027 FeatureInfoFlags::PDCM
2028 );
2029
2030 check_flag!(
2031 doc = "Process-context identifiers. A value of 1 indicates that the processor \
2032 supports PCIDs and the software may set CR4.PCIDE to 1.",
2033 has_pcid,
2034 edx_ecx,
2035 FeatureInfoFlags::PCID
2036 );
2037
2038 check_flag!(
2039 doc = "A value of 1 indicates the processor supports the ability to prefetch \
2040 data from a memory mapped device.",
2041 has_dca,
2042 edx_ecx,
2043 FeatureInfoFlags::DCA
2044 );
2045
2046 check_flag!(
2047 doc = "A value of 1 indicates that the processor supports SSE4.1.",
2048 has_sse41,
2049 edx_ecx,
2050 FeatureInfoFlags::SSE41
2051 );
2052
2053 check_flag!(
2054 doc = "A value of 1 indicates that the processor supports SSE4.2.",
2055 has_sse42,
2056 edx_ecx,
2057 FeatureInfoFlags::SSE42
2058 );
2059
2060 check_flag!(
2061 doc = "A value of 1 indicates that the processor supports x2APIC feature.",
2062 has_x2apic,
2063 edx_ecx,
2064 FeatureInfoFlags::X2APIC
2065 );
2066
2067 check_flag!(
2068 doc = "A value of 1 indicates that the processor supports MOVBE instruction.",
2069 has_movbe,
2070 edx_ecx,
2071 FeatureInfoFlags::MOVBE
2072 );
2073
2074 check_flag!(
2075 doc = "A value of 1 indicates that the processor supports the POPCNT instruction.",
2076 has_popcnt,
2077 edx_ecx,
2078 FeatureInfoFlags::POPCNT
2079 );
2080
2081 check_flag!(
2082 doc = "A value of 1 indicates that the processors local APIC timer supports \
2083 one-shot operation using a TSC deadline value.",
2084 has_tsc_deadline,
2085 edx_ecx,
2086 FeatureInfoFlags::TSC_DEADLINE
2087 );
2088
2089 check_flag!(
2090 doc = "A value of 1 indicates that the processor supports the AESNI instruction \
2091 extensions.",
2092 has_aesni,
2093 edx_ecx,
2094 FeatureInfoFlags::AESNI
2095 );
2096
2097 check_flag!(
2098 doc = "A value of 1 indicates that the processor supports the XSAVE/XRSTOR \
2099 processor extended states feature, the XSETBV/XGETBV instructions, and \
2100 XCR0.",
2101 has_xsave,
2102 edx_ecx,
2103 FeatureInfoFlags::XSAVE
2104 );
2105
2106 check_flag!(
2107 doc = "A value of 1 indicates that the OS has enabled XSETBV/XGETBV instructions \
2108 to access XCR0, and support for processor extended state management using \
2109 XSAVE/XRSTOR.",
2110 has_oxsave,
2111 edx_ecx,
2112 FeatureInfoFlags::OSXSAVE
2113 );
2114
2115 check_flag!(
2116 doc = "A value of 1 indicates the processor supports the AVX instruction \
2117 extensions.",
2118 has_avx,
2119 edx_ecx,
2120 FeatureInfoFlags::AVX
2121 );
2122
2123 check_flag!(
2124 doc = "A value of 1 indicates that processor supports 16-bit floating-point \
2125 conversion instructions.",
2126 has_f16c,
2127 edx_ecx,
2128 FeatureInfoFlags::F16C
2129 );
2130
2131 check_flag!(
2132 doc = "A value of 1 indicates that processor supports RDRAND instruction.",
2133 has_rdrand,
2134 edx_ecx,
2135 FeatureInfoFlags::RDRAND
2136 );
2137
2138 check_flag!(
2139 doc = "A value of 1 indicates the indicates the presence of a hypervisor.",
2140 has_hypervisor,
2141 edx_ecx,
2142 FeatureInfoFlags::HYPERVISOR
2143 );
2144
2145 check_flag!(
2146 doc = "Floating Point Unit On-Chip. The processor contains an x87 FPU.",
2147 has_fpu,
2148 edx_ecx,
2149 FeatureInfoFlags::FPU
2150 );
2151
2152 check_flag!(
2153 doc = "Virtual 8086 Mode Enhancements. Virtual 8086 mode enhancements, including \
2154 CR4.VME for controlling the feature, CR4.PVI for protected mode virtual \
2155 interrupts, software interrupt indirection, expansion of the TSS with the \
2156 software indirection bitmap, and EFLAGS.VIF and EFLAGS.VIP flags.",
2157 has_vme,
2158 edx_ecx,
2159 FeatureInfoFlags::VME
2160 );
2161
2162 check_flag!(
2163 doc = "Debugging Extensions. Support for I/O breakpoints, including CR4.DE for \
2164 controlling the feature, and optional trapping of accesses to DR4 and DR5.",
2165 has_de,
2166 edx_ecx,
2167 FeatureInfoFlags::DE
2168 );
2169
2170 check_flag!(
2171 doc = "Page Size Extension. Large pages of size 4 MByte are supported, including \
2172 CR4.PSE for controlling the feature, the defined dirty bit in PDE (Page \
2173 Directory Entries), optional reserved bit trapping in CR3, PDEs, and PTEs.",
2174 has_pse,
2175 edx_ecx,
2176 FeatureInfoFlags::PSE
2177 );
2178
2179 check_flag!(
2180 doc = "Time Stamp Counter. The RDTSC instruction is supported, including CR4.TSD \
2181 for controlling privilege.",
2182 has_tsc,
2183 edx_ecx,
2184 FeatureInfoFlags::TSC
2185 );
2186
2187 check_flag!(
2188 doc = "Model Specific Registers RDMSR and WRMSR Instructions. The RDMSR and \
2189 WRMSR instructions are supported. Some of the MSRs are implementation \
2190 dependent.",
2191 has_msr,
2192 edx_ecx,
2193 FeatureInfoFlags::MSR
2194 );
2195
2196 check_flag!(
2197 doc = "Physical Address Extension. Physical addresses greater than 32 bits are \
2198 supported: extended page table entry formats, an extra level in the page \
2199 translation tables is defined, 2-MByte pages are supported instead of 4 \
2200 Mbyte pages if PAE bit is 1.",
2201 has_pae,
2202 edx_ecx,
2203 FeatureInfoFlags::PAE
2204 );
2205
2206 check_flag!(
2207 doc = "Machine Check Exception. Exception 18 is defined for Machine Checks, \
2208 including CR4.MCE for controlling the feature. This feature does not \
2209 define the model-specific implementations of machine-check error logging, \
2210 reporting, and processor shutdowns. Machine Check exception handlers may \
2211 have to depend on processor version to do model specific processing of \
2212 the exception, or test for the presence of the Machine Check feature.",
2213 has_mce,
2214 edx_ecx,
2215 FeatureInfoFlags::MCE
2216 );
2217
2218 check_flag!(
2219 doc = "CMPXCHG8B Instruction. The compare-and-exchange 8 bytes (64 bits) \
2220 instruction is supported (implicitly locked and atomic).",
2221 has_cmpxchg8b,
2222 edx_ecx,
2223 FeatureInfoFlags::CX8
2224 );
2225
2226 check_flag!(
2227 doc = "APIC On-Chip. The processor contains an Advanced Programmable Interrupt \
2228 Controller (APIC), responding to memory mapped commands in the physical \
2229 address range FFFE0000H to FFFE0FFFH (by default - some processors permit \
2230 the APIC to be relocated).",
2231 has_apic,
2232 edx_ecx,
2233 FeatureInfoFlags::APIC
2234 );
2235
2236 check_flag!(
2237 doc = "SYSENTER and SYSEXIT Instructions. The SYSENTER and SYSEXIT and \
2238 associated MSRs are supported.",
2239 has_sysenter_sysexit,
2240 edx_ecx,
2241 FeatureInfoFlags::SEP
2242 );
2243
2244 check_flag!(
2245 doc = "Memory Type Range Registers. MTRRs are supported. The MTRRcap MSR \
2246 contains feature bits that describe what memory types are supported, how \
2247 many variable MTRRs are supported, and whether fixed MTRRs are supported.",
2248 has_mtrr,
2249 edx_ecx,
2250 FeatureInfoFlags::MTRR
2251 );
2252
2253 check_flag!(
2254 doc = "Page Global Bit. The global bit is supported in paging-structure entries \
2255 that map a page, indicating TLB entries that are common to different \
2256 processes and need not be flushed. The CR4.PGE bit controls this feature.",
2257 has_pge,
2258 edx_ecx,
2259 FeatureInfoFlags::PGE
2260 );
2261
2262 check_flag!(
2263 doc = "Machine Check Architecture. A value of 1 indicates the Machine Check \
2264 Architecture of reporting machine errors is supported. The MCG_CAP MSR \
2265 contains feature bits describing how many banks of error reporting MSRs \
2266 are supported.",
2267 has_mca,
2268 edx_ecx,
2269 FeatureInfoFlags::MCA
2270 );
2271
2272 check_flag!(
2273 doc = "Conditional Move Instructions. The conditional move instruction CMOV is \
2274 supported. In addition, if x87 FPU is present as indicated by the \
2275 CPUID.FPU feature bit, then the FCOMI and FCMOV instructions are supported",
2276 has_cmov,
2277 edx_ecx,
2278 FeatureInfoFlags::CMOV
2279 );
2280
2281 check_flag!(
2282 doc = "Page Attribute Table. Page Attribute Table is supported. This feature \
2283 augments the Memory Type Range Registers (MTRRs), allowing an operating \
2284 system to specify attributes of memory accessed through a linear address \
2285 on a 4KB granularity.",
2286 has_pat,
2287 edx_ecx,
2288 FeatureInfoFlags::PAT
2289 );
2290
2291 check_flag!(
2292 doc = "36-Bit Page Size Extension. 4-MByte pages addressing physical memory \
2293 beyond 4 GBytes are supported with 32-bit paging. This feature indicates \
2294 that upper bits of the physical address of a 4-MByte page are encoded in \
2295 bits 20:13 of the page-directory entry. Such physical addresses are \
2296 limited by MAXPHYADDR and may be up to 40 bits in size.",
2297 has_pse36,
2298 edx_ecx,
2299 FeatureInfoFlags::PSE36
2300 );
2301
2302 check_flag!(
2303 doc = "Processor Serial Number. The processor supports the 96-bit processor \
2304 identification number feature and the feature is enabled.",
2305 has_psn,
2306 edx_ecx,
2307 FeatureInfoFlags::PSN
2308 );
2309
2310 check_flag!(
2311 doc = "CLFLUSH Instruction. CLFLUSH Instruction is supported.",
2312 has_clflush,
2313 edx_ecx,
2314 FeatureInfoFlags::CLFSH
2315 );
2316
2317 check_flag!(
2318 doc = "Debug Store. The processor supports the ability to write debug \
2319 information into a memory resident buffer. This feature is used by the \
2320 branch trace store (BTS) and processor event-based sampling (PEBS) \
2321 facilities (see Chapter 23, Introduction to Virtual-Machine Extensions, \
2322 in the Intel® 64 and IA-32 Architectures Software Developers Manual, \
2323 Volume 3C).",
2324 has_ds,
2325 edx_ecx,
2326 FeatureInfoFlags::DS
2327 );
2328
2329 check_flag!(
2330 doc = "Thermal Monitor and Software Controlled Clock Facilities. The processor \
2331 implements internal MSRs that allow processor temperature to be monitored \
2332 and processor performance to be modulated in predefined duty cycles under \
2333 software control.",
2334 has_acpi,
2335 edx_ecx,
2336 FeatureInfoFlags::ACPI
2337 );
2338
2339 check_flag!(
2340 doc = "Intel MMX Technology. The processor supports the Intel MMX technology.",
2341 has_mmx,
2342 edx_ecx,
2343 FeatureInfoFlags::MMX
2344 );
2345
2346 check_flag!(
2347 doc = "FXSAVE and FXRSTOR Instructions. The FXSAVE and FXRSTOR instructions are \
2348 supported for fast save and restore of the floating point context. \
2349 Presence of this bit also indicates that CR4.OSFXSR is available for an \
2350 operating system to indicate that it supports the FXSAVE and FXRSTOR \
2351 instructions.",
2352 has_fxsave_fxstor,
2353 edx_ecx,
2354 FeatureInfoFlags::FXSR
2355 );
2356
2357 check_flag!(
2358 doc = "SSE. The processor supports the SSE extensions.",
2359 has_sse,
2360 edx_ecx,
2361 FeatureInfoFlags::SSE
2362 );
2363
2364 check_flag!(
2365 doc = "SSE2. The processor supports the SSE2 extensions.",
2366 has_sse2,
2367 edx_ecx,
2368 FeatureInfoFlags::SSE2
2369 );
2370
2371 check_flag!(
2372 doc = "Self Snoop. The processor supports the management of conflicting memory \
2373 types by performing a snoop of its own cache structure for transactions \
2374 issued to the bus.",
2375 has_ss,
2376 edx_ecx,
2377 FeatureInfoFlags::SS
2378 );
2379
2380 check_flag!(
2381 doc = "Max APIC IDs reserved field is Valid. A value of 0 for HTT indicates \
2382 there is only a single logical processor in the package and software \
2383 should assume only a single APIC ID is reserved. A value of 1 for HTT \
2384 indicates the value in CPUID.1.EBX\\[23:16\\] (the Maximum number of \
2385 addressable IDs for logical processors in this package) is valid for the \
2386 package.",
2387 has_htt,
2388 edx_ecx,
2389 FeatureInfoFlags::HTT
2390 );
2391
2392 check_flag!(
2393 doc = "Thermal Monitor. The processor implements the thermal monitor automatic \
2394 thermal control circuitry (TCC).",
2395 has_tm,
2396 edx_ecx,
2397 FeatureInfoFlags::TM
2398 );
2399
2400 check_flag!(
2401 doc = "Pending Break Enable. The processor supports the use of the FERR#/PBE# \
2402 pin when the processor is in the stop-clock state (STPCLK# is asserted) \
2403 to signal the processor that an interrupt is pending and that the \
2404 processor should return to normal operation to handle the interrupt. Bit \
2405 10 (PBE enable) in the IA32_MISC_ENABLE MSR enables this capability.",
2406 has_pbe,
2407 edx_ecx,
2408 FeatureInfoFlags::PBE
2409 );
2410}
2411
2412impl Debug for FeatureInfo {
2413 fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
2414 f.debug_struct("FeatureInfo")
2415 .field("extended_family_id", &self.extended_family_id())
2416 .field("extended_model_id", &self.extended_model_id())
2417 .field("family_id", &self.family_id())
2418 .field("model_id", &self.model_id())
2419 .field("stepping_id", &self.stepping_id())
2420 .field("brand_index", &self.brand_index())
2421 .field("cflush_cache_line_size", &self.cflush_cache_line_size())
2422 .field("initial_local_apic_id", &self.initial_local_apic_id())
2423 .field(
2424 "max_logical_processor_ids",
2425 &self.max_logical_processor_ids(),
2426 )
2427 .field("edx_ecx", &self.edx_ecx)
2428 .finish()
2429 }
2430}
2431
2432bitflags! {
2433 #[repr(transparent)]
2434 #[derive(Debug, Clone, Copy, PartialEq, Eq)]
2435 struct FeatureInfoFlags: u64 {
2436 const SSE3 = 1 << 0;
2440 const PCLMULQDQ = 1 << 1;
2442 const DTES64 = 1 << 2;
2444 const MONITOR = 1 << 3;
2446 const DSCPL = 1 << 4;
2448 const VMX = 1 << 5;
2450 const SMX = 1 << 6;
2452 const EIST = 1 << 7;
2454 const TM2 = 1 << 8;
2456 const SSSE3 = 1 << 9;
2458 const CNXTID = 1 << 10;
2460 const FMA = 1 << 12;
2462 const CMPXCHG16B = 1 << 13;
2464 const PDCM = 1 << 15;
2466 const PCID = 1 << 17;
2468 const DCA = 1 << 18;
2470 const SSE41 = 1 << 19;
2472 const SSE42 = 1 << 20;
2474 const X2APIC = 1 << 21;
2476 const MOVBE = 1 << 22;
2478 const POPCNT = 1 << 23;
2480 const TSC_DEADLINE = 1 << 24;
2482 const AESNI = 1 << 25;
2484 const XSAVE = 1 << 26;
2486 const OSXSAVE = 1 << 27;
2488 const AVX = 1 << 28;
2490 const F16C = 1 << 29;
2492 const RDRAND = 1 << 30;
2494 const HYPERVISOR = 1 << 31;
2496
2497
2498 const FPU = 1 << 32;
2502 const VME = 1 << (32 + 1);
2504 const DE = 1 << (32 + 2);
2506 const PSE = 1 << (32 + 3);
2508 const TSC = 1 << (32 + 4);
2510 const MSR = 1 << (32 + 5);
2512 const PAE = 1 << (32 + 6);
2514 const MCE = 1 << (32 + 7);
2516 const CX8 = 1 << (32 + 8);
2518 const APIC = 1 << (32 + 9);
2520 const SEP = 1 << (32 + 11);
2522 const MTRR = 1 << (32 + 12);
2524 const PGE = 1 << (32 + 13);
2526 const MCA = 1 << (32 + 14);
2528 const CMOV = 1 << (32 + 15);
2530 const PAT = 1 << (32 + 16);
2532 const PSE36 = 1 << (32 + 17);
2534 const PSN = 1 << (32 + 18);
2536 const CLFSH = 1 << (32 + 19);
2538 const DS = 1 << (32 + 21);
2540 const ACPI = 1 << (32 + 22);
2542 const MMX = 1 << (32 + 23);
2544 const FXSR = 1 << (32 + 24);
2546 const SSE = 1 << (32 + 25);
2548 const SSE2 = 1 << (32 + 26);
2550 const SS = 1 << (32 + 27);
2552 const HTT = 1 << (32 + 28);
2554 const TM = 1 << (32 + 29);
2556 const PBE = 1 << (32 + 31);
2558 }
2559}
2560
2561#[derive(Clone, Copy)]
2568pub struct CacheParametersIter<R: CpuIdReader> {
2569 read: R,
2570 leaf: u32,
2571 current: u32,
2572}
2573
2574impl<R: CpuIdReader> Iterator for CacheParametersIter<R> {
2575 type Item = CacheParameter;
2576
2577 fn next(&mut self) -> Option<CacheParameter> {
2583 let res = self.read.cpuid2(self.leaf, self.current);
2584 let cp = CacheParameter {
2585 eax: res.eax,
2586 ebx: res.ebx,
2587 ecx: res.ecx,
2588 edx: res.edx,
2589 };
2590
2591 match cp.cache_type() {
2592 CacheType::Null => None,
2593 CacheType::Reserved => None,
2594 _ => {
2595 self.current += 1;
2596 Some(cp)
2597 }
2598 }
2599 }
2600}
2601
2602impl<R: CpuIdReader> Debug for CacheParametersIter<R> {
2603 fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
2604 let mut debug = f.debug_list();
2605 self.clone().for_each(|ref item| {
2606 debug.entry(item);
2607 });
2608 debug.finish()
2609 }
2610}
2611
2612#[derive(Copy, Clone, Eq, PartialEq)]
2617pub struct CacheParameter {
2618 eax: u32,
2619 ebx: u32,
2620 ecx: u32,
2621 edx: u32,
2622}
2623
2624#[derive(PartialEq, Eq, Debug)]
2626pub enum CacheType {
2627 Null = 0,
2629 Data,
2631 Instruction,
2633 Unified,
2635 Reserved,
2637}
2638
2639impl fmt::Display for CacheType {
2640 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2641 let typ = match self {
2642 CacheType::Null => "Null",
2643 CacheType::Data => "Data",
2644 CacheType::Instruction => "Instruction",
2645 CacheType::Unified => "Unified",
2646 CacheType::Reserved => "Reserved",
2647 };
2648
2649 f.write_str(typ)
2650 }
2651}
2652
2653impl CacheParameter {
2654 pub fn cache_type(&self) -> CacheType {
2659 let typ = get_bits(self.eax, 0, 4) as u8;
2660 match typ {
2661 0 => CacheType::Null,
2662 1 => CacheType::Data,
2663 2 => CacheType::Instruction,
2664 3 => CacheType::Unified,
2665 _ => CacheType::Reserved,
2666 }
2667 }
2668
2669 pub fn level(&self) -> u8 {
2674 get_bits(self.eax, 5, 7) as u8
2675 }
2676
2677 pub fn is_self_initializing(&self) -> bool {
2682 get_bits(self.eax, 8, 8) == 1
2683 }
2684
2685 pub fn is_fully_associative(&self) -> bool {
2690 get_bits(self.eax, 9, 9) == 1
2691 }
2692
2693 pub fn max_cores_for_cache(&self) -> usize {
2698 (get_bits(self.eax, 14, 25) + 1) as usize
2699 }
2700
2701 pub fn max_cores_for_package(&self) -> usize {
2706 (get_bits(self.eax, 26, 31) + 1) as usize
2707 }
2708
2709 pub fn coherency_line_size(&self) -> usize {
2714 (get_bits(self.ebx, 0, 11) + 1) as usize
2715 }
2716
2717 pub fn physical_line_partitions(&self) -> usize {
2722 (get_bits(self.ebx, 12, 21) + 1) as usize
2723 }
2724
2725 pub fn associativity(&self) -> usize {
2730 (get_bits(self.ebx, 22, 31) + 1) as usize
2731 }
2732
2733 pub fn sets(&self) -> usize {
2738 (self.ecx + 1) as usize
2739 }
2740
2741 pub fn is_write_back_invalidate(&self) -> bool {
2748 get_bits(self.edx, 0, 0) == 1
2749 }
2750
2751 pub fn is_inclusive(&self) -> bool {
2758 get_bits(self.edx, 1, 1) == 1
2759 }
2760
2761 pub fn has_complex_indexing(&self) -> bool {
2768 get_bits(self.edx, 2, 2) == 1
2769 }
2770}
2771
2772impl Debug for CacheParameter {
2773 fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
2774 f.debug_struct("CacheParameter")
2775 .field("cache_type", &self.cache_type())
2776 .field("level", &self.level())
2777 .field("is_self_initializing", &self.is_self_initializing())
2778 .field("is_fully_associative", &self.is_fully_associative())
2779 .field("max_cores_for_cache", &self.max_cores_for_cache())
2780 .field("max_cores_for_package", &self.max_cores_for_package())
2781 .field("coherency_line_size", &self.coherency_line_size())
2782 .field("physical_line_partitions", &self.physical_line_partitions())
2783 .field("associativity", &self.associativity())
2784 .field("sets", &self.sets())
2785 .field("is_write_back_invalidate", &self.is_write_back_invalidate())
2786 .field("is_inclusive", &self.is_inclusive())
2787 .field("has_complex_indexing", &self.has_complex_indexing())
2788 .finish()
2789 }
2790}
2791
2792#[derive(Eq, PartialEq)]
2797pub struct MonitorMwaitInfo {
2798 eax: u32,
2799 ebx: u32,
2800 ecx: u32,
2801 edx: u32,
2802}
2803
2804impl MonitorMwaitInfo {
2805 pub fn smallest_monitor_line(&self) -> u16 {
2810 get_bits(self.eax, 0, 15) as u16
2811 }
2812
2813 pub fn largest_monitor_line(&self) -> u16 {
2818 get_bits(self.ebx, 0, 15) as u16
2819 }
2820
2821 pub fn extensions_supported(&self) -> bool {
2826 get_bits(self.ecx, 0, 0) == 1
2827 }
2828
2829 pub fn interrupts_as_break_event(&self) -> bool {
2834 get_bits(self.ecx, 1, 1) == 1
2835 }
2836
2837 pub fn supported_c0_states(&self) -> u16 {
2842 get_bits(self.edx, 0, 3) as u16
2843 }
2844
2845 pub fn supported_c1_states(&self) -> u16 {
2850 get_bits(self.edx, 4, 7) as u16
2851 }
2852
2853 pub fn supported_c2_states(&self) -> u16 {
2858 get_bits(self.edx, 8, 11) as u16
2859 }
2860
2861 pub fn supported_c3_states(&self) -> u16 {
2866 get_bits(self.edx, 12, 15) as u16
2867 }
2868
2869 pub fn supported_c4_states(&self) -> u16 {
2874 get_bits(self.edx, 16, 19) as u16
2875 }
2876
2877 pub fn supported_c5_states(&self) -> u16 {
2882 get_bits(self.edx, 20, 23) as u16
2883 }
2884
2885 pub fn supported_c6_states(&self) -> u16 {
2890 get_bits(self.edx, 24, 27) as u16
2891 }
2892
2893 pub fn supported_c7_states(&self) -> u16 {
2898 get_bits(self.edx, 28, 31) as u16
2899 }
2900}
2901
2902impl Debug for MonitorMwaitInfo {
2903 fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
2904 f.debug_struct("MonitorMwaitInfo")
2905 .field("smallest_monitor_line", &self.smallest_monitor_line())
2906 .field("largest_monitor_line", &self.largest_monitor_line())
2907 .field("extensions_supported", &self.extensions_supported())
2908 .field(
2909 "interrupts_as_break_event",
2910 &self.interrupts_as_break_event(),
2911 )
2912 .field("supported_c0_states", &self.supported_c0_states())
2913 .field("supported_c1_states", &self.supported_c1_states())
2914 .field("supported_c2_states", &self.supported_c2_states())
2915 .field("supported_c3_states", &self.supported_c3_states())
2916 .field("supported_c4_states", &self.supported_c4_states())
2917 .field("supported_c5_states", &self.supported_c5_states())
2918 .field("supported_c6_states", &self.supported_c6_states())
2919 .field("supported_c7_states", &self.supported_c7_states())
2920 .finish()
2921 }
2922}
2923
2924pub struct ThermalPowerInfo {
2929 eax: ThermalPowerFeaturesEax,
2930 ebx: u32,
2931 ecx: ThermalPowerFeaturesEcx,
2932 _edx: u32,
2933}
2934
2935impl ThermalPowerInfo {
2936 pub fn dts_irq_threshold(&self) -> u8 {
2941 get_bits(self.ebx, 0, 3) as u8
2942 }
2943
2944 pub fn has_dts(&self) -> bool {
2949 self.eax.contains(ThermalPowerFeaturesEax::DTS)
2950 }
2951
2952 pub fn has_turbo_boost(&self) -> bool {
2958 self.eax.contains(ThermalPowerFeaturesEax::TURBO_BOOST)
2959 }
2960
2961 pub fn has_arat(&self) -> bool {
2966 self.eax.contains(ThermalPowerFeaturesEax::ARAT)
2967 }
2968
2969 pub fn has_pln(&self) -> bool {
2974 self.eax.contains(ThermalPowerFeaturesEax::PLN)
2975 }
2976
2977 pub fn has_ecmd(&self) -> bool {
2982 self.eax.contains(ThermalPowerFeaturesEax::ECMD)
2983 }
2984
2985 pub fn has_ptm(&self) -> bool {
2990 self.eax.contains(ThermalPowerFeaturesEax::PTM)
2991 }
2992
2993 pub fn has_hwp(&self) -> bool {
2999 self.eax.contains(ThermalPowerFeaturesEax::HWP)
3000 }
3001
3002 pub fn has_hwp_notification(&self) -> bool {
3007 self.eax.contains(ThermalPowerFeaturesEax::HWP_NOTIFICATION)
3008 }
3009
3010 pub fn has_hwp_activity_window(&self) -> bool {
3015 self.eax
3016 .contains(ThermalPowerFeaturesEax::HWP_ACTIVITY_WINDOW)
3017 }
3018
3019 pub fn has_hwp_energy_performance_preference(&self) -> bool {
3025 self.eax
3026 .contains(ThermalPowerFeaturesEax::HWP_ENERGY_PERFORMANCE_PREFERENCE)
3027 }
3028
3029 pub fn has_hwp_package_level_request(&self) -> bool {
3034 self.eax
3035 .contains(ThermalPowerFeaturesEax::HWP_PACKAGE_LEVEL_REQUEST)
3036 }
3037
3038 pub fn has_hdc(&self) -> bool {
3044 self.eax.contains(ThermalPowerFeaturesEax::HDC)
3045 }
3046
3047 pub fn has_turbo_boost3(&self) -> bool {
3052 self.eax.contains(ThermalPowerFeaturesEax::TURBO_BOOST_3)
3053 }
3054
3055 pub fn has_hwp_capabilities(&self) -> bool {
3060 self.eax.contains(ThermalPowerFeaturesEax::HWP_CAPABILITIES)
3061 }
3062
3063 pub fn has_hwp_peci_override(&self) -> bool {
3068 self.eax
3069 .contains(ThermalPowerFeaturesEax::HWP_PECI_OVERRIDE)
3070 }
3071
3072 pub fn has_flexible_hwp(&self) -> bool {
3077 self.eax.contains(ThermalPowerFeaturesEax::FLEXIBLE_HWP)
3078 }
3079
3080 pub fn has_hwp_fast_access_mode(&self) -> bool {
3085 self.eax
3086 .contains(ThermalPowerFeaturesEax::HWP_REQUEST_MSR_FAST_ACCESS)
3087 }
3088
3089 pub fn has_ignore_idle_processor_hwp_request(&self) -> bool {
3094 self.eax
3095 .contains(ThermalPowerFeaturesEax::IGNORE_IDLE_PROCESSOR_HWP_REQUEST)
3096 }
3097
3098 pub fn has_hw_coord_feedback(&self) -> bool {
3110 self.ecx
3111 .contains(ThermalPowerFeaturesEcx::HW_COORD_FEEDBACK)
3112 }
3113
3114 pub fn has_energy_bias_pref(&self) -> bool {
3121 self.ecx.contains(ThermalPowerFeaturesEcx::ENERGY_BIAS_PREF)
3122 }
3123}
3124
3125impl Debug for ThermalPowerInfo {
3126 fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
3127 f.debug_struct("ThermalPowerInfo")
3128 .field("dts_irq_threshold", &self.dts_irq_threshold())
3129 .field("has_dts", &self.has_dts())
3130 .field("has_arat", &self.has_arat())
3131 .field("has_pln", &self.has_pln())
3132 .field("has_ecmd", &self.has_ecmd())
3133 .field("has_ptm", &self.has_ptm())
3134 .field("has_hwp", &self.has_hwp())
3135 .field("has_hwp_notification", &self.has_hwp_notification())
3136 .field("has_hwp_activity_window", &self.has_hwp_activity_window())
3137 .field(
3138 "has_hwp_energy_performance_preference",
3139 &self.has_hwp_energy_performance_preference(),
3140 )
3141 .field(
3142 "has_hwp_package_level_request",
3143 &self.has_hwp_package_level_request(),
3144 )
3145 .field("has_hdc", &self.has_hdc())
3146 .field("has_turbo_boost3", &self.has_turbo_boost3())
3147 .field("has_hwp_capabilities", &self.has_hwp_capabilities())
3148 .field("has_hwp_peci_override", &self.has_hwp_peci_override())
3149 .field("has_flexible_hwp", &self.has_flexible_hwp())
3150 .field("has_hwp_fast_access_mode", &self.has_hwp_fast_access_mode())
3151 .field(
3152 "has_ignore_idle_processor_hwp_request",
3153 &self.has_ignore_idle_processor_hwp_request(),
3154 )
3155 .field("has_hw_coord_feedback", &self.has_hw_coord_feedback())
3156 .field("has_energy_bias_pref", &self.has_energy_bias_pref())
3157 .finish()
3158 }
3159}
3160
3161bitflags! {
3162 struct ThermalPowerFeaturesEax: u32 {
3163 const DTS = 1 << 0;
3165 const TURBO_BOOST = 1 << 1;
3167 const ARAT = 1 << 2;
3169 const RESERVED_3 = 1 << 3;
3171 const PLN = 1 << 4;
3173 const ECMD = 1 << 5;
3175 const PTM = 1 << 6;
3177 const HWP = 1 << 7;
3179 const HWP_NOTIFICATION = 1 << 8;
3181 const HWP_ACTIVITY_WINDOW = 1 << 9;
3183 const HWP_ENERGY_PERFORMANCE_PREFERENCE = 1 << 10;
3185 const HWP_PACKAGE_LEVEL_REQUEST = 1 << 11;
3187 const RESERVED_12 = 1 << 12;
3189 const HDC = 1 << 13;
3191 const TURBO_BOOST_3 = 1 << 14;
3193 const HWP_CAPABILITIES = 1 << 15;
3195 const HWP_PECI_OVERRIDE = 1 << 16;
3197 const FLEXIBLE_HWP = 1 << 17;
3199 const HWP_REQUEST_MSR_FAST_ACCESS = 1 << 18;
3201 const RESERVED_19 = 1 << 19;
3203 const IGNORE_IDLE_PROCESSOR_HWP_REQUEST = 1 << 20;
3205 }
3207}
3208
3209bitflags! {
3210 struct ThermalPowerFeaturesEcx: u32 {
3211 const HW_COORD_FEEDBACK = 1 << 0;
3212
3213 const ENERGY_BIAS_PREF = 1 << 3;
3215 }
3216}
3217
3218pub struct ExtendedFeatures {
3223 _eax: u32,
3224 ebx: ExtendedFeaturesEbx,
3225 ecx: ExtendedFeaturesEcx,
3226 edx: ExtendedFeaturesEdx,
3227 eax1: ExtendedFeaturesEax1,
3228 _ebx1: u32,
3229 _ecx1: u32,
3230 edx1: ExtendedFeaturesEdx1,
3231}
3232
3233impl ExtendedFeatures {
3234 #[inline]
3239 pub const fn has_fsgsbase(&self) -> bool {
3240 self.ebx.contains(ExtendedFeaturesEbx::FSGSBASE)
3241 }
3242
3243 #[inline]
3248 pub const fn has_tsc_adjust_msr(&self) -> bool {
3249 self.ebx.contains(ExtendedFeaturesEbx::ADJUST_MSR)
3250 }
3251
3252 #[inline]
3257 pub const fn has_bmi1(&self) -> bool {
3258 self.ebx.contains(ExtendedFeaturesEbx::BMI1)
3259 }
3260
3261 #[inline]
3266 pub const fn has_hle(&self) -> bool {
3267 self.ebx.contains(ExtendedFeaturesEbx::HLE)
3268 }
3269
3270 #[inline]
3275 pub const fn has_avx2(&self) -> bool {
3276 self.ebx.contains(ExtendedFeaturesEbx::AVX2)
3277 }
3278
3279 #[inline]
3285 pub const fn has_fdp(&self) -> bool {
3286 self.ebx.contains(ExtendedFeaturesEbx::FDP)
3287 }
3288
3289 #[inline]
3294 pub const fn has_smep(&self) -> bool {
3295 self.ebx.contains(ExtendedFeaturesEbx::SMEP)
3296 }
3297
3298 #[inline]
3303 pub const fn has_bmi2(&self) -> bool {
3304 self.ebx.contains(ExtendedFeaturesEbx::BMI2)
3305 }
3306
3307 #[inline]
3312 pub const fn has_rep_movsb_stosb(&self) -> bool {
3313 self.ebx.contains(ExtendedFeaturesEbx::REP_MOVSB_STOSB)
3314 }
3315
3316 #[inline]
3322 pub const fn has_invpcid(&self) -> bool {
3323 self.ebx.contains(ExtendedFeaturesEbx::INVPCID)
3324 }
3325
3326 #[inline]
3331 pub const fn has_rtm(&self) -> bool {
3332 self.ebx.contains(ExtendedFeaturesEbx::RTM)
3333 }
3334
3335 #[inline]
3340 pub const fn has_rdtm(&self) -> bool {
3341 self.ebx.contains(ExtendedFeaturesEbx::RDTM)
3342 }
3343
3344 #[inline]
3349 pub const fn has_fpu_cs_ds_deprecated(&self) -> bool {
3350 self.ebx.contains(ExtendedFeaturesEbx::DEPRECATE_FPU_CS_DS)
3351 }
3352
3353 #[inline]
3358 pub const fn has_mpx(&self) -> bool {
3359 self.ebx.contains(ExtendedFeaturesEbx::MPX)
3360 }
3361
3362 #[inline]
3367 pub const fn has_rdta(&self) -> bool {
3368 self.ebx.contains(ExtendedFeaturesEbx::RDTA)
3369 }
3370
3371 #[inline]
3376 pub const fn has_rdseed(&self) -> bool {
3377 self.ebx.contains(ExtendedFeaturesEbx::RDSEED)
3378 }
3379
3380 #[inline]
3385 pub const fn has_adx(&self) -> bool {
3386 self.ebx.contains(ExtendedFeaturesEbx::ADX)
3387 }
3388
3389 #[inline]
3395 pub const fn has_smap(&self) -> bool {
3396 self.ebx.contains(ExtendedFeaturesEbx::SMAP)
3397 }
3398
3399 #[inline]
3404 pub const fn has_clflushopt(&self) -> bool {
3405 self.ebx.contains(ExtendedFeaturesEbx::CLFLUSHOPT)
3406 }
3407
3408 #[inline]
3413 pub const fn has_processor_trace(&self) -> bool {
3414 self.ebx.contains(ExtendedFeaturesEbx::PROCESSOR_TRACE)
3415 }
3416
3417 #[inline]
3422 pub const fn has_sha(&self) -> bool {
3423 self.ebx.contains(ExtendedFeaturesEbx::SHA)
3424 }
3425
3426 #[inline]
3431 pub const fn has_sgx(&self) -> bool {
3432 self.ebx.contains(ExtendedFeaturesEbx::SGX)
3433 }
3434
3435 #[inline]
3440 pub const fn has_avx512f(&self) -> bool {
3441 self.ebx.contains(ExtendedFeaturesEbx::AVX512F)
3442 }
3443
3444 #[inline]
3449 pub const fn has_avx512dq(&self) -> bool {
3450 self.ebx.contains(ExtendedFeaturesEbx::AVX512DQ)
3451 }
3452
3453 #[inline]
3458 pub const fn has_avx512_ifma(&self) -> bool {
3459 self.ebx.contains(ExtendedFeaturesEbx::AVX512_IFMA)
3460 }
3461
3462 #[inline]
3467 pub const fn has_avx512pf(&self) -> bool {
3468 self.ebx.contains(ExtendedFeaturesEbx::AVX512PF)
3469 }
3470
3471 #[inline]
3476 pub const fn has_avx512er(&self) -> bool {
3477 self.ebx.contains(ExtendedFeaturesEbx::AVX512ER)
3478 }
3479
3480 #[inline]
3485 pub const fn has_avx512cd(&self) -> bool {
3486 self.ebx.contains(ExtendedFeaturesEbx::AVX512CD)
3487 }
3488
3489 #[inline]
3494 pub const fn has_avx512bw(&self) -> bool {
3495 self.ebx.contains(ExtendedFeaturesEbx::AVX512BW)
3496 }
3497
3498 #[inline]
3503 pub const fn has_avx512vl(&self) -> bool {
3504 self.ebx.contains(ExtendedFeaturesEbx::AVX512VL)
3505 }
3506
3507 #[inline]
3512 pub const fn has_clwb(&self) -> bool {
3513 self.ebx.contains(ExtendedFeaturesEbx::CLWB)
3514 }
3515
3516 #[inline]
3521 pub const fn has_prefetchwt1(&self) -> bool {
3522 self.ecx.contains(ExtendedFeaturesEcx::PREFETCHWT1)
3523 }
3524
3525 #[inline]
3530 pub const fn has_umip(&self) -> bool {
3531 self.ecx.contains(ExtendedFeaturesEcx::UMIP)
3532 }
3533
3534 #[inline]
3539 pub const fn has_pku(&self) -> bool {
3540 self.ecx.contains(ExtendedFeaturesEcx::PKU)
3541 }
3542
3543 #[inline]
3549 pub const fn has_ospke(&self) -> bool {
3550 self.ecx.contains(ExtendedFeaturesEcx::OSPKE)
3551 }
3552
3553 #[inline]
3557 pub const fn has_waitpkg(&self) -> bool {
3558 self.ecx.contains(ExtendedFeaturesEcx::WAITPKG)
3559 }
3560
3561 #[inline]
3565 pub const fn has_av512vbmi2(&self) -> bool {
3566 self.ecx.contains(ExtendedFeaturesEcx::AVX512VBMI2)
3567 }
3568
3569 #[inline]
3575 pub const fn has_cet_ss(&self) -> bool {
3576 self.ecx.contains(ExtendedFeaturesEcx::CETSS)
3577 }
3578
3579 #[inline]
3583 pub const fn has_gfni(&self) -> bool {
3584 self.ecx.contains(ExtendedFeaturesEcx::GFNI)
3585 }
3586
3587 #[inline]
3591 pub const fn has_vaes(&self) -> bool {
3592 self.ecx.contains(ExtendedFeaturesEcx::VAES)
3593 }
3594
3595 #[inline]
3599 pub const fn has_vpclmulqdq(&self) -> bool {
3600 self.ecx.contains(ExtendedFeaturesEcx::VPCLMULQDQ)
3601 }
3602
3603 #[inline]
3608 pub const fn has_avx512vnni(&self) -> bool {
3609 self.ecx.contains(ExtendedFeaturesEcx::AVX512VNNI)
3610 }
3611
3612 #[inline]
3616 pub const fn has_avx512bitalg(&self) -> bool {
3617 self.ecx.contains(ExtendedFeaturesEcx::AVX512BITALG)
3618 }
3619
3620 #[inline]
3625 pub const fn has_tme_en(&self) -> bool {
3626 self.ecx.contains(ExtendedFeaturesEcx::TMEEN)
3627 }
3628
3629 #[inline]
3633 pub const fn has_avx512vpopcntdq(&self) -> bool {
3634 self.ecx.contains(ExtendedFeaturesEcx::AVX512VPOPCNTDQ)
3635 }
3636
3637 #[inline]
3642 pub const fn has_la57(&self) -> bool {
3643 self.ecx.contains(ExtendedFeaturesEcx::LA57)
3644 }
3645
3646 #[inline]
3656 pub const fn has_rdpid(&self) -> bool {
3657 self.ecx.contains(ExtendedFeaturesEcx::RDPID)
3658 }
3659
3660 #[inline]
3665 pub const fn has_sgx_lc(&self) -> bool {
3666 self.ecx.contains(ExtendedFeaturesEcx::SGX_LC)
3667 }
3668
3669 #[inline]
3674 pub fn mawau_value(&self) -> u8 {
3675 get_bits(self.ecx.bits(), 17, 21) as u8
3676 }
3677
3678 #[inline]
3683 pub const fn has_avx512_4vnniw(&self) -> bool {
3684 self.edx.contains(ExtendedFeaturesEdx::AVX512_4VNNIW)
3685 }
3686
3687 #[inline]
3692 pub const fn has_avx512_4fmaps(&self) -> bool {
3693 self.edx.contains(ExtendedFeaturesEdx::AVX512_4FMAPS)
3694 }
3695
3696 #[inline]
3701 pub const fn has_avx512_vp2intersect(&self) -> bool {
3702 self.edx.contains(ExtendedFeaturesEdx::AVX512_VP2INTERSECT)
3703 }
3704
3705 #[inline]
3710 pub const fn has_amx_bf16(&self) -> bool {
3711 self.edx.contains(ExtendedFeaturesEdx::AMX_BF16)
3712 }
3713
3714 #[inline]
3719 pub const fn has_avx512_fp16(&self) -> bool {
3720 self.edx.contains(ExtendedFeaturesEdx::AVX512_FP16)
3721 }
3722
3723 #[inline]
3728 pub const fn has_amx_tile(&self) -> bool {
3729 self.edx.contains(ExtendedFeaturesEdx::AMX_TILE)
3730 }
3731
3732 #[inline]
3737 pub const fn has_amx_int8(&self) -> bool {
3738 self.edx.contains(ExtendedFeaturesEdx::AMX_INT8)
3739 }
3740
3741 #[inline]
3746 pub const fn has_avx_vnni(&self) -> bool {
3747 self.eax1.contains(ExtendedFeaturesEax1::AVX_VNNI)
3748 }
3749
3750 #[inline]
3755 pub const fn has_avx512_bf16(&self) -> bool {
3756 self.eax1.contains(ExtendedFeaturesEax1::AVX512_BF16)
3757 }
3758
3759 #[inline]
3764 pub const fn has_fzrm(&self) -> bool {
3765 self.eax1.contains(ExtendedFeaturesEax1::FZRM)
3766 }
3767
3768 #[inline]
3773 pub const fn has_fsrs(&self) -> bool {
3774 self.eax1.contains(ExtendedFeaturesEax1::FSRS)
3775 }
3776
3777 #[inline]
3782 pub const fn has_fsrcrs(&self) -> bool {
3783 self.eax1.contains(ExtendedFeaturesEax1::FSRCRS)
3784 }
3785
3786 #[inline]
3791 pub const fn has_hreset(&self) -> bool {
3792 self.eax1.contains(ExtendedFeaturesEax1::HRESET)
3793 }
3794
3795 #[inline]
3800 pub const fn has_cet_sss(&self) -> bool {
3801 self.edx1.contains(ExtendedFeaturesEdx1::CET_SSS)
3802 }
3803}
3804
3805impl Debug for ExtendedFeatures {
3806 fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
3807 f.debug_struct("ExtendedFeatures")
3808 .field("ebx", &self.ebx)
3809 .field("ecx", &self.ecx)
3810 .field("mawau_value", &self.mawau_value())
3811 .finish()
3812 }
3813}
3814
3815bitflags! {
3816 #[repr(transparent)]
3817 #[derive(Debug, Clone, Copy, PartialEq, Eq)]
3818 struct ExtendedFeaturesEbx: u32 {
3819 const FSGSBASE = 1 << 0;
3821 const ADJUST_MSR = 1 << 1;
3823 const SGX = 1 << 2;
3825 const BMI1 = 1 << 3;
3827 const HLE = 1 << 4;
3829 const AVX2 = 1 << 5;
3831 const FDP = 1 << 6;
3833 const SMEP = 1 << 7;
3835 const BMI2 = 1 << 8;
3837 const REP_MOVSB_STOSB = 1 << 9;
3839 const INVPCID = 1 << 10;
3841 const RTM = 1 << 11;
3843 const RDTM = 1 << 12;
3845 const DEPRECATE_FPU_CS_DS = 1 << 13;
3847 const MPX = 1 << 14;
3849 const RDTA = 1 << 15;
3851 const AVX512F = 1 << 16;
3853 const AVX512DQ = 1 << 17;
3855 const RDSEED = 1 << 18;
3857 const ADX = 1 << 19;
3859 const SMAP = 1 << 20;
3861 const AVX512_IFMA = 1 << 21;
3863 const CLFLUSHOPT = 1 << 23;
3866 const CLWB = 1 << 24;
3868 const PROCESSOR_TRACE = 1 << 25;
3870 const AVX512PF = 1 << 26;
3872 const AVX512ER = 1 << 27;
3874 const AVX512CD = 1 << 28;
3876 const SHA = 1 << 29;
3878 const AVX512BW = 1 << 30;
3880 const AVX512VL = 1 << 31;
3882 }
3883}
3884
3885bitflags! {
3886 #[repr(transparent)]
3887 #[derive(Debug, Clone, Copy, PartialEq, Eq)]
3888 struct ExtendedFeaturesEcx: u32 {
3889 const PREFETCHWT1 = 1 << 0;
3891 const AVX512VBMI = 1 << 1;
3893 const UMIP = 1 << 2;
3895 const PKU = 1 << 3;
3897 const OSPKE = 1 << 4;
3899 const WAITPKG = 1 << 5;
3901 const AVX512VBMI2 = 1 << 6;
3903 const CETSS = 1 << 7;
3907 const GFNI = 1 << 8;
3909 const VAES = 1 << 9;
3911 const VPCLMULQDQ = 1 << 10;
3913 const AVX512VNNI = 1 << 11;
3915 const AVX512BITALG = 1 << 12;
3917 const TMEEN = 1 << 13;
3920 const AVX512VPOPCNTDQ = 1 << 14;
3922
3923 const LA57 = 1 << 16;
3927
3928 const RDPID = 1 << 22;
3932
3933 const SGX_LC = 1 << 30;
3937 }
3938}
3939
3940bitflags! {
3941 #[repr(transparent)]
3942 #[derive(Debug, Clone, Copy, PartialEq, Eq)]
3943 struct ExtendedFeaturesEdx: u32 {
3944 const AVX512_4VNNIW = 1 << 2;
3946 const AVX512_4FMAPS = 1 << 3;
3948 const AVX512_VP2INTERSECT = 1 << 8;
3950 const AMX_BF16 = 1 << 22;
3952 const AVX512_FP16 = 1 << 23;
3954 const AMX_TILE = 1 << 24;
3956 const AMX_INT8 = 1 << 25;
3958 }
3959}
3960
3961bitflags! {
3962 #[repr(transparent)]
3963 #[derive(Debug, Clone, Copy, PartialEq, Eq)]
3964 struct ExtendedFeaturesEax1: u32 {
3965 const AVX_VNNI = 1 << 4;
3968 const AVX512_BF16 = 1 << 5;
3970 const FZRM = 1 << 10;
3972 const FSRS = 1 << 11;
3974 const FSRCRS = 1 << 12;
3976 const HRESET = 1 << 22;
3978 }
3979}
3980
3981bitflags! {
3982 #[repr(transparent)]
3983 #[derive(Debug, Clone, Copy, PartialEq, Eq)]
3984 struct ExtendedFeaturesEdx1: u32 {
3985 const CET_SSS = 1 << 18;
3988 }
3989}
3990
3991pub struct DirectCacheAccessInfo {
3996 eax: u32,
3997}
3998
3999impl DirectCacheAccessInfo {
4000 pub fn get_dca_cap_value(&self) -> u32 {
4002 self.eax
4003 }
4004}
4005
4006impl Debug for DirectCacheAccessInfo {
4007 fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
4008 f.debug_struct("DirectCacheAccessInfo")
4009 .field("dca_cap_value", &self.get_dca_cap_value())
4010 .finish()
4011 }
4012}
4013
4014pub struct PerformanceMonitoringInfo {
4019 eax: u32,
4020 ebx: PerformanceMonitoringFeaturesEbx,
4021 _ecx: u32,
4022 edx: u32,
4023}
4024
4025impl PerformanceMonitoringInfo {
4026 pub fn version_id(&self) -> u8 {
4028 get_bits(self.eax, 0, 7) as u8
4029 }
4030
4031 pub fn number_of_counters(&self) -> u8 {
4033 get_bits(self.eax, 8, 15) as u8
4034 }
4035
4036 pub fn counter_bit_width(&self) -> u8 {
4038 get_bits(self.eax, 16, 23) as u8
4039 }
4040
4041 pub fn ebx_length(&self) -> u8 {
4043 get_bits(self.eax, 24, 31) as u8
4044 }
4045
4046 pub fn fixed_function_counters(&self) -> u8 {
4048 get_bits(self.edx, 0, 4) as u8
4049 }
4050
4051 pub fn fixed_function_counters_bit_width(&self) -> u8 {
4053 get_bits(self.edx, 5, 12) as u8
4054 }
4055
4056 check_bit_fn!(
4057 doc = "AnyThread deprecation",
4058 has_any_thread_deprecation,
4059 edx,
4060 15
4061 );
4062
4063 check_flag!(
4064 doc = "Core cycle event not available if 1.",
4065 is_core_cyc_ev_unavailable,
4066 ebx,
4067 PerformanceMonitoringFeaturesEbx::CORE_CYC_EV_UNAVAILABLE
4068 );
4069
4070 check_flag!(
4071 doc = "Instruction retired event not available if 1.",
4072 is_inst_ret_ev_unavailable,
4073 ebx,
4074 PerformanceMonitoringFeaturesEbx::INST_RET_EV_UNAVAILABLE
4075 );
4076
4077 check_flag!(
4078 doc = "Reference cycles event not available if 1.",
4079 is_ref_cycle_ev_unavailable,
4080 ebx,
4081 PerformanceMonitoringFeaturesEbx::REF_CYC_EV_UNAVAILABLE
4082 );
4083
4084 check_flag!(
4085 doc = "Last-level cache reference event not available if 1.",
4086 is_cache_ref_ev_unavailable,
4087 ebx,
4088 PerformanceMonitoringFeaturesEbx::CACHE_REF_EV_UNAVAILABLE
4089 );
4090
4091 check_flag!(
4092 doc = "Last-level cache misses event not available if 1.",
4093 is_ll_cache_miss_ev_unavailable,
4094 ebx,
4095 PerformanceMonitoringFeaturesEbx::LL_CACHE_MISS_EV_UNAVAILABLE
4096 );
4097
4098 check_flag!(
4099 doc = "Branch instruction retired event not available if 1.",
4100 is_branch_inst_ret_ev_unavailable,
4101 ebx,
4102 PerformanceMonitoringFeaturesEbx::BRANCH_INST_RET_EV_UNAVAILABLE
4103 );
4104
4105 check_flag!(
4106 doc = "Branch mispredict retired event not available if 1.",
4107 is_branch_midpred_ev_unavailable,
4108 ebx,
4109 PerformanceMonitoringFeaturesEbx::BRANCH_MISPRED_EV_UNAVAILABLE
4110 );
4111}
4112
4113impl Debug for PerformanceMonitoringInfo {
4114 fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
4115 f.debug_struct("PerformanceMonitoringInfo")
4116 .field("version_id", &self.version_id())
4117 .field("number_of_counters", &self.number_of_counters())
4118 .field("counter_bit_width", &self.counter_bit_width())
4119 .field("ebx_length", &self.ebx_length())
4120 .field("fixed_function_counters", &self.fixed_function_counters())
4121 .field(
4122 "fixed_function_counters_bit_width",
4123 &self.fixed_function_counters_bit_width(),
4124 )
4125 .finish()
4126 }
4127}
4128
4129bitflags! {
4130 #[repr(transparent)]
4131 #[derive(Debug, Clone, Copy, PartialEq, Eq)]
4132 struct PerformanceMonitoringFeaturesEbx: u32 {
4133 const CORE_CYC_EV_UNAVAILABLE = 1 << 0;
4135 const INST_RET_EV_UNAVAILABLE = 1 << 1;
4137 const REF_CYC_EV_UNAVAILABLE = 1 << 2;
4139 const CACHE_REF_EV_UNAVAILABLE = 1 << 3;
4141 const LL_CACHE_MISS_EV_UNAVAILABLE = 1 << 4;
4143 const BRANCH_INST_RET_EV_UNAVAILABLE = 1 << 5;
4145 const BRANCH_MISPRED_EV_UNAVAILABLE = 1 << 6;
4147 }
4148}
4149
4150#[derive(Clone)]
4159pub struct ExtendedTopologyIter<R: CpuIdReader> {
4160 read: R,
4161 level: u32,
4162 is_v2: bool,
4163}
4164
4165#[derive(PartialEq, Eq)]
4169pub struct ExtendedTopologyLevel {
4170 eax: u32,
4171 ebx: u32,
4172 ecx: u32,
4173 edx: u32,
4174}
4175
4176impl fmt::Debug for ExtendedTopologyLevel {
4177 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
4178 f.debug_struct("ExtendedTopologyLevel")
4179 .field("processors", &self.processors())
4180 .field("number", &self.level_number())
4181 .field("type", &self.level_type())
4182 .field("x2apic_id", &self.x2apic_id())
4183 .field("next_apic_id", &self.shift_right_for_next_apic_id())
4184 .finish()
4185 }
4186}
4187
4188impl ExtendedTopologyLevel {
4189 pub fn processors(&self) -> u16 {
4192 get_bits(self.ebx, 0, 15) as u16
4193 }
4194
4195 pub fn level_number(&self) -> u8 {
4197 get_bits(self.ecx, 0, 7) as u8
4198 }
4199
4200 pub fn level_type(&self) -> TopologyType {
4202 match get_bits(self.ecx, 8, 15) {
4203 0 => TopologyType::Invalid,
4204 1 => TopologyType::SMT,
4205 2 => TopologyType::Core,
4206 3 => TopologyType::Module,
4207 4 => TopologyType::Tile,
4208 5 => TopologyType::Die,
4209 _ => unreachable!(),
4210 }
4211 }
4212
4213 pub fn x2apic_id(&self) -> u32 {
4215 self.edx
4216 }
4217
4218 pub fn shift_right_for_next_apic_id(&self) -> u32 {
4221 get_bits(self.eax, 0, 4)
4222 }
4223}
4224
4225#[derive(PartialEq, Eq, Debug)]
4227pub enum TopologyType {
4228 Invalid = 0,
4229 SMT = 1,
4231 Core = 2,
4232 Module = 3,
4233 Tile = 4,
4234 Die = 5,
4235}
4236
4237impl fmt::Display for TopologyType {
4238 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
4239 let data = match self {
4240 TopologyType::Invalid => "Invalid",
4241 TopologyType::SMT => "SMT",
4242 TopologyType::Core => "Core",
4243 TopologyType::Module => "Module",
4244 TopologyType::Tile => "Tile",
4245 TopologyType::Die => "Die",
4246 };
4247
4248 f.write_str(data)
4249 }
4250}
4251
4252impl<R: CpuIdReader> Iterator for ExtendedTopologyIter<R> {
4253 type Item = ExtendedTopologyLevel;
4254
4255 fn next(&mut self) -> Option<ExtendedTopologyLevel> {
4256 let res = if self.is_v2 {
4257 self.read.cpuid2(EAX_EXTENDED_TOPOLOGY_INFO_V2, self.level)
4258 } else {
4259 self.read.cpuid2(EAX_EXTENDED_TOPOLOGY_INFO, self.level)
4260 };
4261 self.level += 1;
4262
4263 let et = ExtendedTopologyLevel {
4264 eax: res.eax,
4265 ebx: res.ebx,
4266 ecx: res.ecx,
4267 edx: res.edx,
4268 };
4269
4270 match et.level_type() {
4271 TopologyType::Invalid => None,
4272 _ => Some(et),
4273 }
4274 }
4275}
4276
4277impl<R: CpuIdReader> Debug for ExtendedTopologyIter<R> {
4278 fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
4279 let mut debug = f.debug_list();
4280 self.clone().for_each(|ref item| {
4281 debug.entry(item);
4282 });
4283 debug.finish()
4284 }
4285}
4286
4287bitflags! {
4288 #[repr(transparent)]
4289 #[derive(Debug, Clone, Copy, PartialEq, Eq)]
4290 struct ExtendedStateInfoXCR0Flags: u32 {
4291 const LEGACY_X87 = 1 << 0;
4293
4294 const SSE128 = 1 << 1;
4296
4297 const AVX256 = 1 << 2;
4299
4300 const MPX_BNDREGS = 1 << 3;
4302
4303 const MPX_BNDCSR = 1 << 4;
4305
4306 const AVX512_OPMASK = 1 << 5;
4308
4309 const AVX512_ZMM_HI256 = 1 << 6;
4311
4312 const AVX512_ZMM_HI16 = 1 << 7;
4314
4315 const PKRU = 1 << 9;
4317
4318 const IA32_XSS_HDC = 1 << 13;
4320
4321 const AMX_TILECFG = 1 << 17;
4323
4324 const AMX_TILEDATA = 1 << 18;
4326 }
4327}
4328
4329bitflags! {
4330 #[repr(transparent)]
4331 #[derive(Debug, Clone, Copy, PartialEq, Eq)]
4332 struct ExtendedStateInfoXSSFlags: u32 {
4333 const PT = 1 << 8;
4335
4336 const PASID = 1 << 10;
4338
4339 const CET_USER = 1 << 11;
4341
4342 const CET_SUPERVISOR = 1 << 12;
4344
4345 const HDC = 1 << 13;
4347
4348 const UINTR = 1 << 14;
4350
4351 const LBR = 1 << 15;
4353
4354 const HWP = 1 << 16;
4356 }
4357}
4358
4359pub struct ExtendedStateInfo<R: CpuIdReader> {
4364 read: R,
4365 eax: ExtendedStateInfoXCR0Flags,
4366 ebx: u32,
4367 ecx: u32,
4368 _edx: u32,
4369 eax1: u32,
4370 ebx1: u32,
4371 ecx1: ExtendedStateInfoXSSFlags,
4372 _edx1: u32,
4373}
4374
4375impl<F: CpuIdReader> ExtendedStateInfo<F> {
4376 check_flag!(
4377 doc = "Support for legacy x87 in XCR0.",
4378 xcr0_supports_legacy_x87,
4379 eax,
4380 ExtendedStateInfoXCR0Flags::LEGACY_X87
4381 );
4382
4383 check_flag!(
4384 doc = "Support for SSE 128-bit in XCR0.",
4385 xcr0_supports_sse_128,
4386 eax,
4387 ExtendedStateInfoXCR0Flags::SSE128
4388 );
4389
4390 check_flag!(
4391 doc = "Support for AVX 256-bit in XCR0.",
4392 xcr0_supports_avx_256,
4393 eax,
4394 ExtendedStateInfoXCR0Flags::AVX256
4395 );
4396
4397 check_flag!(
4398 doc = "Support for MPX BNDREGS in XCR0.",
4399 xcr0_supports_mpx_bndregs,
4400 eax,
4401 ExtendedStateInfoXCR0Flags::MPX_BNDREGS
4402 );
4403
4404 check_flag!(
4405 doc = "Support for MPX BNDCSR in XCR0.",
4406 xcr0_supports_mpx_bndcsr,
4407 eax,
4408 ExtendedStateInfoXCR0Flags::MPX_BNDCSR
4409 );
4410
4411 check_flag!(
4412 doc = "Support for AVX512 OPMASK in XCR0.",
4413 xcr0_supports_avx512_opmask,
4414 eax,
4415 ExtendedStateInfoXCR0Flags::AVX512_OPMASK
4416 );
4417
4418 check_flag!(
4419 doc = "Support for AVX512 ZMM Hi256 XCR0.",
4420 xcr0_supports_avx512_zmm_hi256,
4421 eax,
4422 ExtendedStateInfoXCR0Flags::AVX512_ZMM_HI256
4423 );
4424
4425 check_flag!(
4426 doc = "Support for AVX512 ZMM Hi16 in XCR0.",
4427 xcr0_supports_avx512_zmm_hi16,
4428 eax,
4429 ExtendedStateInfoXCR0Flags::AVX512_ZMM_HI16
4430 );
4431
4432 check_flag!(
4433 doc = "Support for PKRU in XCR0.",
4434 xcr0_supports_pkru,
4435 eax,
4436 ExtendedStateInfoXCR0Flags::PKRU
4437 );
4438
4439 check_flag!(
4440 doc = "Support for PT in IA32_XSS.",
4441 ia32_xss_supports_pt,
4442 ecx1,
4443 ExtendedStateInfoXSSFlags::PT
4444 );
4445
4446 check_flag!(
4447 doc = "Support for HDC in IA32_XSS.",
4448 ia32_xss_supports_hdc,
4449 ecx1,
4450 ExtendedStateInfoXSSFlags::HDC
4451 );
4452
4453 pub fn xsave_area_size_enabled_features(&self) -> u32 {
4457 self.ebx
4458 }
4459
4460 pub fn xsave_area_size_supported_features(&self) -> u32 {
4464 self.ecx
4465 }
4466
4467 pub fn has_xsaveopt(&self) -> bool {
4469 self.eax1 & 0x1 > 0
4470 }
4471
4472 pub fn has_xsavec(&self) -> bool {
4474 self.eax1 & 0b10 > 0
4475 }
4476
4477 pub fn has_xgetbv(&self) -> bool {
4479 self.eax1 & 0b100 > 0
4480 }
4481
4482 pub fn has_xsaves_xrstors(&self) -> bool {
4484 self.eax1 & 0b1000 > 0
4485 }
4486
4487 pub fn xsave_size(&self) -> u32 {
4489 self.ebx1
4490 }
4491
4492 pub fn iter(&self) -> ExtendedStateIter<F> {
4494 ExtendedStateIter {
4495 read: self.read.clone(),
4496 level: 1,
4497 supported_xcr0: self.eax.bits(),
4498 supported_xss: self.ecx1.bits(),
4499 }
4500 }
4501}
4502
4503impl<R: CpuIdReader> Debug for ExtendedStateInfo<R> {
4504 fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
4505 f.debug_struct("ExtendedStateInfo")
4506 .field("eax", &self.eax)
4507 .field("ecx1", &self.ecx1)
4508 .field(
4509 "xsave_area_size_enabled_features",
4510 &self.xsave_area_size_enabled_features(),
4511 )
4512 .field(
4513 "xsave_area_size_supported_features",
4514 &self.xsave_area_size_supported_features(),
4515 )
4516 .field("has_xsaveopt", &self.has_xsaveopt())
4517 .field("has_xsavec", &self.has_xsavec())
4518 .field("has_xgetbv", &self.has_xgetbv())
4519 .field("has_xsaves_xrstors", &self.has_xsaves_xrstors())
4520 .field("xsave_size", &self.xsave_size())
4521 .field("extended_state_iter", &self.iter())
4522 .finish()
4523 }
4524}
4525
4526#[derive(Clone)]
4528pub struct ExtendedStateIter<R: CpuIdReader> {
4529 read: R,
4530 level: u32,
4531 supported_xcr0: u32,
4532 supported_xss: u32,
4533}
4534
4535impl<R: CpuIdReader> Iterator for ExtendedStateIter<R> {
4542 type Item = ExtendedState;
4543
4544 fn next(&mut self) -> Option<ExtendedState> {
4545 self.level += 1;
4546 if self.level > 31 {
4547 return None;
4548 }
4549
4550 let bit = 1 << self.level;
4551 if (self.supported_xcr0 & bit > 0) || (self.supported_xss & bit > 0) {
4552 let res = self.read.cpuid2(EAX_EXTENDED_STATE_INFO, self.level);
4553 return Some(ExtendedState {
4554 subleaf: self.level,
4555 eax: res.eax,
4556 ebx: res.ebx,
4557 ecx: res.ecx,
4558 });
4559 }
4560
4561 self.next()
4562 }
4563}
4564
4565impl<R: CpuIdReader> Debug for ExtendedStateIter<R> {
4566 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
4567 let mut debug = f.debug_list();
4568 self.clone().for_each(|ref item| {
4569 debug.entry(item);
4570 });
4571 debug.finish()
4572 }
4573}
4574
4575#[derive(PartialEq, Eq, Debug)]
4577#[repr(u32)]
4578pub enum ExtendedRegisterType {
4579 Avx,
4580 MpxBndregs,
4581 MpxBndcsr,
4582 Avx512Opmask,
4583 Avx512ZmmHi256,
4584 Avx512ZmmHi16,
4585 Pt,
4586 Pkru,
4587 Hdc,
4588 Unknown(u32),
4589}
4590
4591impl From<u32> for ExtendedRegisterType {
4592 fn from(value: u32) -> ExtendedRegisterType {
4593 match value {
4594 0x2 => ExtendedRegisterType::Avx,
4595 0x3 => ExtendedRegisterType::MpxBndregs,
4596 0x4 => ExtendedRegisterType::MpxBndcsr,
4597 0x5 => ExtendedRegisterType::Avx512Opmask,
4598 0x6 => ExtendedRegisterType::Avx512ZmmHi256,
4599 0x7 => ExtendedRegisterType::Avx512ZmmHi16,
4600 0x8 => ExtendedRegisterType::Pt,
4601 0x9 => ExtendedRegisterType::Pkru,
4602 0xd => ExtendedRegisterType::Hdc,
4603 x => ExtendedRegisterType::Unknown(x),
4604 }
4605 }
4606}
4607
4608impl fmt::Display for ExtendedRegisterType {
4609 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
4610 let data = match self {
4611 ExtendedRegisterType::Avx => "AVX/YMM",
4612 ExtendedRegisterType::MpxBndregs => "MPX BNDREGS",
4613 ExtendedRegisterType::MpxBndcsr => "MPX BNDCSR",
4614 ExtendedRegisterType::Avx512Opmask => "AVX-512 opmask",
4615 ExtendedRegisterType::Avx512ZmmHi256 => "AVX-512 ZMM_Hi256",
4616 ExtendedRegisterType::Avx512ZmmHi16 => "AVX-512 Hi16_ZMM",
4617 ExtendedRegisterType::Pkru => "PKRU",
4618 ExtendedRegisterType::Pt => "PT",
4619 ExtendedRegisterType::Hdc => "HDC",
4620 ExtendedRegisterType::Unknown(t) => {
4621 return write!(f, "Unknown({})", t);
4622 }
4623 };
4624
4625 f.write_str(data)
4626 }
4627}
4628
4629#[derive(PartialEq, Eq, Debug)]
4631pub enum ExtendedRegisterStateLocation {
4632 Xcr0,
4633 Ia32Xss,
4634}
4635
4636impl fmt::Display for ExtendedRegisterStateLocation {
4637 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
4638 let data = match self {
4639 ExtendedRegisterStateLocation::Xcr0 => "XCR0 (user state)",
4640 ExtendedRegisterStateLocation::Ia32Xss => "IA32_XSS (supervisor state)",
4641 };
4642
4643 f.write_str(data)
4644 }
4645}
4646
4647pub struct ExtendedState {
4649 pub subleaf: u32,
4650 eax: u32,
4651 ebx: u32,
4652 ecx: u32,
4653}
4654
4655impl ExtendedState {
4656 pub fn register(&self) -> ExtendedRegisterType {
4658 self.subleaf.into()
4659 }
4660
4661 pub fn size(&self) -> u32 {
4665 self.eax
4666 }
4667
4668 pub fn offset(&self) -> u32 {
4671 self.ebx
4672 }
4673
4674 pub fn location(&self) -> ExtendedRegisterStateLocation {
4675 if self.is_in_xcr0() {
4676 ExtendedRegisterStateLocation::Xcr0
4677 } else {
4678 ExtendedRegisterStateLocation::Ia32Xss
4679 }
4680 }
4681
4682 pub fn is_in_ia32_xss(&self) -> bool {
4688 self.ecx & 0b1 > 0
4689 }
4690
4691 pub fn is_in_xcr0(&self) -> bool {
4696 self.ecx & 0b1 == 0
4697 }
4698
4699 pub fn is_compacted_format(&self) -> bool {
4704 self.ecx & 0b10 > 0
4705 }
4706}
4707
4708impl Debug for ExtendedState {
4709 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
4710 f.debug_struct("ExtendedState")
4711 .field("size", &self.size())
4712 .field("offset", &self.offset())
4713 .field("is_in_ia32_xss", &self.is_in_ia32_xss())
4714 .field("is_in_xcr0", &self.is_in_xcr0())
4715 .field("is_compacted_format", &self.is_compacted_format())
4716 .finish()
4717 }
4718}
4719
4720pub struct RdtMonitoringInfo<R: CpuIdReader> {
4726 read: R,
4727 ebx: u32,
4728 edx: u32,
4729}
4730
4731impl<R: CpuIdReader> RdtMonitoringInfo<R> {
4732 pub fn rmid_range(&self) -> u32 {
4734 self.ebx
4735 }
4736
4737 check_bit_fn!(
4738 doc = "Supports L3 Cache Intel RDT Monitoring.",
4739 has_l3_monitoring,
4740 edx,
4741 1
4742 );
4743
4744 pub fn l3_monitoring(&self) -> Option<L3MonitoringInfo> {
4746 if self.has_l3_monitoring() {
4747 let res = self.read.cpuid2(EAX_RDT_MONITORING, 1);
4748 Some(L3MonitoringInfo {
4749 ebx: res.ebx,
4750 ecx: res.ecx,
4751 edx: res.edx,
4752 })
4753 } else {
4754 None
4755 }
4756 }
4757}
4758
4759impl<R: CpuIdReader> Debug for RdtMonitoringInfo<R> {
4760 fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
4761 f.debug_struct("RdtMonitoringInfo")
4762 .field("rmid_range", &self.rmid_range())
4763 .field("l3_monitoring", &self.l3_monitoring())
4764 .finish()
4765 }
4766}
4767
4768pub struct L3MonitoringInfo {
4770 ebx: u32,
4771 ecx: u32,
4772 edx: u32,
4773}
4774
4775impl L3MonitoringInfo {
4776 pub fn conversion_factor(&self) -> u32 {
4778 self.ebx
4779 }
4780
4781 pub fn maximum_rmid_range(&self) -> u32 {
4783 self.ecx
4784 }
4785
4786 check_bit_fn!(
4787 doc = "Supports occupancy monitoring.",
4788 has_occupancy_monitoring,
4789 edx,
4790 0
4791 );
4792
4793 check_bit_fn!(
4794 doc = "Supports total bandwidth monitoring.",
4795 has_total_bandwidth_monitoring,
4796 edx,
4797 1
4798 );
4799
4800 check_bit_fn!(
4801 doc = "Supports local bandwidth monitoring.",
4802 has_local_bandwidth_monitoring,
4803 edx,
4804 2
4805 );
4806}
4807
4808impl Debug for L3MonitoringInfo {
4809 fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
4810 f.debug_struct("L3MonitoringInfo")
4811 .field("conversion_factor", &self.conversion_factor())
4812 .field("maximum_rmid_range", &self.maximum_rmid_range())
4813 .finish()
4814 }
4815}
4816
4817pub struct RdtAllocationInfo<R: CpuIdReader> {
4822 read: R,
4823 ebx: u32,
4824}
4825
4826impl<R: CpuIdReader> RdtAllocationInfo<R> {
4827 check_bit_fn!(doc = "Supports L3 Cache Allocation.", has_l3_cat, ebx, 1);
4828
4829 check_bit_fn!(doc = "Supports L2 Cache Allocation.", has_l2_cat, ebx, 2);
4830
4831 check_bit_fn!(
4832 doc = "Supports Memory Bandwidth Allocation.",
4833 has_memory_bandwidth_allocation,
4834 ebx,
4835 3
4836 );
4837
4838 pub fn l3_cat(&self) -> Option<L3CatInfo> {
4840 if self.has_l3_cat() {
4841 let res = self.read.cpuid2(EAX_RDT_ALLOCATION, 1);
4842 Some(L3CatInfo {
4843 eax: res.eax,
4844 ebx: res.ebx,
4845 ecx: res.ecx,
4846 edx: res.edx,
4847 })
4848 } else {
4849 None
4850 }
4851 }
4852
4853 pub fn l2_cat(&self) -> Option<L2CatInfo> {
4855 if self.has_l2_cat() {
4856 let res = self.read.cpuid2(EAX_RDT_ALLOCATION, 2);
4857 Some(L2CatInfo {
4858 eax: res.eax,
4859 ebx: res.ebx,
4860 edx: res.edx,
4861 })
4862 } else {
4863 None
4864 }
4865 }
4866
4867 pub fn memory_bandwidth_allocation(&self) -> Option<MemBwAllocationInfo> {
4869 if self.has_memory_bandwidth_allocation() {
4870 let res = self.read.cpuid2(EAX_RDT_ALLOCATION, 3);
4871 Some(MemBwAllocationInfo {
4872 eax: res.eax,
4873 ecx: res.ecx,
4874 edx: res.edx,
4875 })
4876 } else {
4877 None
4878 }
4879 }
4880}
4881
4882impl<R: CpuIdReader> Debug for RdtAllocationInfo<R> {
4883 fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
4884 f.debug_struct("RdtAllocationInfo")
4885 .field("l3_cat", &self.l3_cat())
4886 .field("l2_cat", &self.l2_cat())
4887 .field(
4888 "memory_bandwidth_allocation",
4889 &self.memory_bandwidth_allocation(),
4890 )
4891 .finish()
4892 }
4893}
4894
4895pub struct L3CatInfo {
4897 eax: u32,
4898 ebx: u32,
4899 ecx: u32,
4900 edx: u32,
4901}
4902
4903impl L3CatInfo {
4904 pub fn capacity_mask_length(&self) -> u8 {
4906 (get_bits(self.eax, 0, 4) + 1) as u8
4907 }
4908
4909 pub fn isolation_bitmap(&self) -> u32 {
4911 self.ebx
4912 }
4913
4914 pub fn highest_cos(&self) -> u16 {
4916 get_bits(self.edx, 0, 15) as u16
4917 }
4918
4919 check_bit_fn!(
4920 doc = "Is Code and Data Prioritization Technology supported?",
4921 has_code_data_prioritization,
4922 ecx,
4923 2
4924 );
4925}
4926
4927impl Debug for L3CatInfo {
4928 fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
4929 f.debug_struct("L3CatInfo")
4930 .field("capacity_mask_length", &self.capacity_mask_length())
4931 .field("isolation_bitmap", &self.isolation_bitmap())
4932 .field("highest_cos", &self.highest_cos())
4933 .finish()
4934 }
4935}
4936
4937#[derive(Eq, PartialEq)]
4939pub struct L2CatInfo {
4940 eax: u32,
4941 ebx: u32,
4942 edx: u32,
4943}
4944
4945impl L2CatInfo {
4946 pub fn capacity_mask_length(&self) -> u8 {
4948 (get_bits(self.eax, 0, 4) + 1) as u8
4949 }
4950
4951 pub fn isolation_bitmap(&self) -> u32 {
4953 self.ebx
4954 }
4955
4956 pub fn highest_cos(&self) -> u16 {
4958 get_bits(self.edx, 0, 15) as u16
4959 }
4960}
4961
4962impl Debug for L2CatInfo {
4963 fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
4964 f.debug_struct("L2CatInfo")
4965 .field("capacity_mask_length", &self.capacity_mask_length())
4966 .field("isolation_bitmap", &self.isolation_bitmap())
4967 .field("highest_cos", &self.highest_cos())
4968 .finish()
4969 }
4970}
4971
4972#[derive(Eq, PartialEq)]
4974pub struct MemBwAllocationInfo {
4975 eax: u32,
4976 ecx: u32,
4977 edx: u32,
4978}
4979
4980impl MemBwAllocationInfo {
4981 pub fn max_hba_throttling(&self) -> u16 {
4983 (get_bits(self.eax, 0, 11) + 1) as u16
4984 }
4985
4986 pub fn highest_cos(&self) -> u16 {
4988 get_bits(self.edx, 0, 15) as u16
4989 }
4990
4991 check_bit_fn!(
4992 doc = "Reports whether the response of the delay values is linear.",
4993 has_linear_response_delay,
4994 ecx,
4995 2
4996 );
4997}
4998
4999impl Debug for MemBwAllocationInfo {
5000 fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
5001 f.debug_struct("MemBwAllocationInfo")
5002 .field("max_hba_throttling", &self.max_hba_throttling())
5003 .field("highest_cos", &self.highest_cos())
5004 .field(
5005 "has_linear_response_delay",
5006 &self.has_linear_response_delay(),
5007 )
5008 .finish()
5009 }
5010}
5011
5012pub struct SgxInfo<R: CpuIdReader> {
5019 read: R,
5020 eax: u32,
5021 ebx: u32,
5022 _ecx: u32,
5023 edx: u32,
5024 eax1: u32,
5025 ebx1: u32,
5026 ecx1: u32,
5027 edx1: u32,
5028}
5029
5030impl<F: CpuIdReader> SgxInfo<F> {
5031 check_bit_fn!(doc = "Has SGX1 support.", has_sgx1, eax, 0);
5032 check_bit_fn!(doc = "Has SGX2 support.", has_sgx2, eax, 1);
5033
5034 check_bit_fn!(
5035 doc = "Supports ENCLV instruction leaves EINCVIRTCHILD, EDECVIRTCHILD, and ESETCONTEXT.",
5036 has_enclv_leaves_einvirtchild_edecvirtchild_esetcontext,
5037 eax,
5038 5
5039 );
5040
5041 check_bit_fn!(
5042 doc = "Supports ENCLS instruction leaves ETRACKC, ERDINFO, ELDBC, and ELDUC.",
5043 has_encls_leaves_etrackc_erdinfo_eldbc_elduc,
5044 eax,
5045 6
5046 );
5047
5048 pub fn miscselect(&self) -> u32 {
5050 self.ebx
5051 }
5052
5053 pub fn max_enclave_size_non_64bit(&self) -> u8 {
5055 get_bits(self.edx, 0, 7) as u8
5056 }
5057
5058 pub fn max_enclave_size_64bit(&self) -> u8 {
5060 get_bits(self.edx, 8, 15) as u8
5061 }
5062
5063 pub fn secs_attributes(&self) -> (u64, u64) {
5065 let lower = self.eax1 as u64 | (self.ebx1 as u64) << 32;
5066 let upper = self.ecx1 as u64 | (self.edx1 as u64) << 32;
5067 (lower, upper)
5068 }
5069 pub fn iter(&self) -> SgxSectionIter<F> {
5071 SgxSectionIter {
5072 read: self.read.clone(),
5073 current: 2,
5074 }
5075 }
5076}
5077
5078impl<R: CpuIdReader> Debug for SgxInfo<R> {
5079 fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
5080 f.debug_struct("SgxInfo")
5081 .field("has_sgx1", &self.has_sgx1())
5082 .field("has_sgx2", &self.has_sgx2())
5083 .field("miscselect", &self.miscselect())
5084 .field(
5085 "max_enclave_size_non_64bit",
5086 &self.max_enclave_size_non_64bit(),
5087 )
5088 .field("max_enclave_size_64bit", &self.max_enclave_size_64bit())
5089 .field(
5090 "has_encls_leaves_etrackc_erdinfo_eldbc_elduc",
5091 &self.has_encls_leaves_etrackc_erdinfo_eldbc_elduc(),
5092 )
5093 .field(
5094 "has_enclv_leaves_einvirtchild_edecvirtchild_esetcontext",
5095 &self.has_enclv_leaves_einvirtchild_edecvirtchild_esetcontext(),
5096 )
5097 .field("sgx_section_iter", &self.iter())
5098 .finish()
5099 }
5100}
5101
5102#[derive(Clone)]
5104pub struct SgxSectionIter<R: CpuIdReader> {
5105 read: R,
5106 current: u32,
5107}
5108
5109impl<R: CpuIdReader> Iterator for SgxSectionIter<R> {
5110 type Item = SgxSectionInfo;
5111
5112 fn next(&mut self) -> Option<SgxSectionInfo> {
5113 let res = self.read.cpuid2(EAX_SGX, self.current);
5114 self.current += 1;
5115 match get_bits(res.eax, 0, 3) {
5116 0b0001 => Some(SgxSectionInfo::Epc(EpcSection {
5117 eax: res.eax,
5118 ebx: res.ebx,
5119 ecx: res.ecx,
5120 edx: res.edx,
5121 })),
5122 _ => None,
5123 }
5124 }
5125}
5126
5127impl<R: CpuIdReader> Debug for SgxSectionIter<R> {
5128 fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
5129 let mut debug = f.debug_list();
5130 self.clone().for_each(|ref item| {
5131 debug.entry(item);
5132 });
5133 debug.finish()
5134 }
5135}
5136
5137#[derive(Debug)]
5141pub enum SgxSectionInfo {
5142 Epc(EpcSection),
5144}
5145
5146#[derive(Debug)]
5148pub struct EpcSection {
5149 eax: u32,
5150 ebx: u32,
5151 ecx: u32,
5152 edx: u32,
5153}
5154
5155impl EpcSection {
5156 pub fn physical_base(&self) -> u64 {
5158 let lower = (get_bits(self.eax, 12, 31) << 12) as u64;
5159 let upper = (get_bits(self.ebx, 0, 19) as u64) << 32;
5160 lower | upper
5161 }
5162
5163 pub fn size(&self) -> u64 {
5165 let lower = (get_bits(self.ecx, 12, 31) << 12) as u64;
5166 let upper = (get_bits(self.edx, 0, 19) as u64) << 32;
5167 lower | upper
5168 }
5169}
5170
5171pub struct ProcessorTraceInfo {
5176 _eax: u32,
5177 ebx: u32,
5178 ecx: u32,
5179 _edx: u32,
5180 leaf1: Option<CpuIdResult>,
5181}
5182
5183impl ProcessorTraceInfo {
5184 check_bit_fn!(
5186 doc = "If true, Indicates that IA32_RTIT_CTL.CR3Filter can be set to 1, and \
5187 that IA32_RTIT_CR3_MATCH MSR can be accessed.",
5188 has_rtit_cr3_match,
5189 ebx,
5190 0
5191 );
5192 check_bit_fn!(
5193 doc = "If true, Indicates support of Configurable PSB and Cycle-Accurate Mode.",
5194 has_configurable_psb_and_cycle_accurate_mode,
5195 ebx,
5196 1
5197 );
5198 check_bit_fn!(
5199 doc = "If true, Indicates support of IP Filtering, TraceStop filtering, and \
5200 preservation of Intel PT MSRs across warm reset.",
5201 has_ip_tracestop_filtering,
5202 ebx,
5203 2
5204 );
5205 check_bit_fn!(
5206 doc = "If true, Indicates support of MTC timing packet and suppression of \
5207 COFI-based packets.",
5208 has_mtc_timing_packet_coefi_suppression,
5209 ebx,
5210 3
5211 );
5212
5213 check_bit_fn!(
5214 doc = "Indicates support of PTWRITE. Writes can set IA32_RTIT_CTL\\[12\\] (PTWEn \
5215 and IA32_RTIT_CTL\\[5\\] (FUPonPTW), and PTWRITE can generate packets",
5216 has_ptwrite,
5217 ebx,
5218 4
5219 );
5220
5221 check_bit_fn!(
5222 doc = "Support of Power Event Trace. Writes can set IA32_RTIT_CTL\\[4\\] (PwrEvtEn) \
5223 enabling Power Event Trace packet generation.",
5224 has_power_event_trace,
5225 ebx,
5226 5
5227 );
5228
5229 check_bit_fn!(
5231 doc = "If true, Tracing can be enabled with IA32_RTIT_CTL.ToPA = 1, hence \
5232 utilizing the ToPA output scheme; IA32_RTIT_OUTPUT_BASE and \
5233 IA32_RTIT_OUTPUT_MASK_PTRS MSRs can be accessed.",
5234 has_topa,
5235 ecx,
5236 0
5237 );
5238 check_bit_fn!(
5239 doc = "If true, ToPA tables can hold any number of output entries, up to the \
5240 maximum allowed by the MaskOrTableOffset field of \
5241 IA32_RTIT_OUTPUT_MASK_PTRS.",
5242 has_topa_maximum_entries,
5243 ecx,
5244 1
5245 );
5246 check_bit_fn!(
5247 doc = "If true, Indicates support of Single-Range Output scheme.",
5248 has_single_range_output_scheme,
5249 ecx,
5250 2
5251 );
5252 check_bit_fn!(
5253 doc = "If true, Indicates support of output to Trace Transport subsystem.",
5254 has_trace_transport_subsystem,
5255 ecx,
5256 3
5257 );
5258 check_bit_fn!(
5259 doc = "If true, Generated packets which contain IP payloads have LIP values, \
5260 which include the CS base component.",
5261 has_lip_with_cs_base,
5262 ecx,
5263 31
5264 );
5265
5266 pub fn configurable_address_ranges(&self) -> u8 {
5268 self.leaf1.map_or(0, |res| get_bits(res.eax, 0, 2) as u8)
5269 }
5270
5271 pub fn supported_mtc_period_encodings(&self) -> u16 {
5273 self.leaf1.map_or(0, |res| get_bits(res.eax, 16, 31) as u16)
5274 }
5275
5276 pub fn supported_cycle_threshold_value_encodings(&self) -> u16 {
5278 self.leaf1.map_or(0, |res| get_bits(res.ebx, 0, 15) as u16)
5279 }
5280
5281 pub fn supported_psb_frequency_encodings(&self) -> u16 {
5283 self.leaf1.map_or(0, |res| get_bits(res.ebx, 16, 31) as u16)
5284 }
5285}
5286
5287impl Debug for ProcessorTraceInfo {
5288 fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
5289 f.debug_struct("ProcessorTraceInfo")
5290 .field(
5291 "configurable_address_ranges",
5292 &self.configurable_address_ranges(),
5293 )
5294 .field(
5295 "supported_mtc_period_encodings",
5296 &self.supported_mtc_period_encodings(),
5297 )
5298 .field(
5299 "supported_cycle_threshold_value_encodings",
5300 &self.supported_cycle_threshold_value_encodings(),
5301 )
5302 .field(
5303 "supported_psb_frequency_encodings",
5304 &self.supported_psb_frequency_encodings(),
5305 )
5306 .finish()
5307 }
5308}
5309
5310pub struct TscInfo {
5315 eax: u32,
5316 ebx: u32,
5317 ecx: u32,
5318}
5319
5320impl fmt::Debug for TscInfo {
5321 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
5322 f.debug_struct("TscInfo")
5323 .field("denominator", &self.denominator())
5324 .field("numerator", &self.numerator())
5325 .field("nominal_frequency", &self.nominal_frequency())
5326 .field("tsc_frequency", &self.tsc_frequency())
5327 .finish()
5328 }
5329}
5330
5331impl TscInfo {
5332 pub fn denominator(&self) -> u32 {
5334 self.eax
5335 }
5336
5337 pub fn numerator(&self) -> u32 {
5341 self.ebx
5342 }
5343
5344 pub fn nominal_frequency(&self) -> u32 {
5348 self.ecx
5349 }
5350
5351 pub fn tsc_frequency(&self) -> Option<u64> {
5353 if self.nominal_frequency() == 0 || self.numerator() == 0 || self.denominator() == 0 {
5356 return None;
5357 }
5358
5359 Some(self.nominal_frequency() as u64 * self.numerator() as u64 / self.denominator() as u64)
5360 }
5361}
5362
5363pub struct ProcessorFrequencyInfo {
5368 eax: u32,
5369 ebx: u32,
5370 ecx: u32,
5371}
5372
5373impl ProcessorFrequencyInfo {
5374 pub fn processor_base_frequency(&self) -> u16 {
5376 get_bits(self.eax, 0, 15) as u16
5377 }
5378
5379 pub fn processor_max_frequency(&self) -> u16 {
5381 get_bits(self.ebx, 0, 15) as u16
5382 }
5383
5384 pub fn bus_frequency(&self) -> u16 {
5386 get_bits(self.ecx, 0, 15) as u16
5387 }
5388}
5389
5390impl fmt::Debug for ProcessorFrequencyInfo {
5391 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
5392 f.debug_struct("ProcessorFrequencyInfo")
5393 .field("processor_base_frequency", &self.processor_base_frequency())
5394 .field("processor_max_frequency", &self.processor_max_frequency())
5395 .field("bus_frequency", &self.bus_frequency())
5396 .finish()
5397 }
5398}
5399
5400#[derive(Clone)]
5405pub struct DatIter<R: CpuIdReader> {
5406 read: R,
5407 current: u32,
5408 count: u32,
5409}
5410
5411impl<R: CpuIdReader> Iterator for DatIter<R> {
5412 type Item = DatInfo;
5413
5414 fn next(&mut self) -> Option<DatInfo> {
5416 loop {
5417 if self.current > self.count {
5419 return None;
5420 }
5421
5422 let res = self
5423 .read
5424 .cpuid2(EAX_DETERMINISTIC_ADDRESS_TRANSLATION_INFO, self.current);
5425 self.current += 1;
5426
5427 if get_bits(res.edx, 0, 4) == 0 {
5429 continue;
5433 }
5434
5435 return Some(DatInfo {
5436 _eax: res.eax,
5437 ebx: res.ebx,
5438 ecx: res.ecx,
5439 edx: res.edx,
5440 });
5441 }
5442 }
5443}
5444
5445impl<R: CpuIdReader> Debug for DatIter<R> {
5446 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
5447 let mut debug = f.debug_list();
5448 self.clone().for_each(|ref item| {
5449 debug.entry(item);
5450 });
5451 debug.finish()
5452 }
5453}
5454
5455pub struct DatInfo {
5457 _eax: u32,
5458 ebx: u32,
5459 ecx: u32,
5460 edx: u32,
5461}
5462
5463impl DatInfo {
5464 check_bit_fn!(
5465 doc = "4K page size entries supported by this structure",
5466 has_4k_entries,
5467 ebx,
5468 0
5469 );
5470
5471 check_bit_fn!(
5472 doc = "2MB page size entries supported by this structure",
5473 has_2mb_entries,
5474 ebx,
5475 1
5476 );
5477
5478 check_bit_fn!(
5479 doc = "4MB page size entries supported by this structure",
5480 has_4mb_entries,
5481 ebx,
5482 2
5483 );
5484
5485 check_bit_fn!(
5486 doc = "1GB page size entries supported by this structure",
5487 has_1gb_entries,
5488 ebx,
5489 3
5490 );
5491
5492 check_bit_fn!(
5493 doc = "Fully associative structure",
5494 is_fully_associative,
5495 edx,
5496 8
5497 );
5498
5499 pub fn partitioning(&self) -> u8 {
5501 get_bits(self.ebx, 8, 10) as u8
5502 }
5503
5504 pub fn ways(&self) -> u16 {
5506 get_bits(self.ebx, 16, 31) as u16
5507 }
5508
5509 pub fn sets(&self) -> u32 {
5511 self.ecx
5512 }
5513
5514 pub fn cache_type(&self) -> DatType {
5516 match get_bits(self.edx, 0, 4) as u8 {
5517 0b00001 => DatType::DataTLB,
5518 0b00010 => DatType::InstructionTLB,
5519 0b00011 => DatType::UnifiedTLB,
5520 0b00000 => DatType::Null, 0b00100 => DatType::LoadOnly,
5522 0b00101 => DatType::StoreOnly,
5523 _ => DatType::Unknown,
5524 }
5525 }
5526
5527 pub fn cache_level(&self) -> u8 {
5529 get_bits(self.edx, 5, 7) as u8
5530 }
5531
5532 pub fn max_addressable_ids(&self) -> u16 {
5534 (get_bits(self.edx, 14, 25) + 1) as u16
5536 }
5537}
5538
5539impl Debug for DatInfo {
5540 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
5541 f.debug_struct("DatInfo")
5542 .field("has_4k_entries", &self.has_4k_entries())
5543 .field("has_2mb_entries", &self.has_2mb_entries())
5544 .field("has_4mb_entries", &self.has_4mb_entries())
5545 .field("has_1gb_entries", &self.has_1gb_entries())
5546 .field("is_fully_associative", &self.is_fully_associative())
5547 .finish()
5548 }
5549}
5550
5551#[derive(Eq, PartialEq, Debug)]
5553pub enum DatType {
5554 Null = 0b00000,
5556 DataTLB = 0b00001,
5557 InstructionTLB = 0b00010,
5558 UnifiedTLB = 0b00011,
5564 LoadOnly = 0b0100,
5565 StoreOnly = 0b0101,
5566 Unknown,
5567}
5568
5569impl fmt::Display for DatType {
5570 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
5571 let t = match self {
5572 DatType::Null => "invalid (0)",
5573 DatType::DataTLB => "Data TLB",
5574 DatType::InstructionTLB => "Instruction TLB",
5575 DatType::UnifiedTLB => "Unified TLB",
5576 DatType::LoadOnly => "Load Only",
5577 DatType::StoreOnly => "Store Only",
5578 DatType::Unknown => "Unknown",
5579 };
5580 f.write_str(t)
5581 }
5582}
5583
5584pub struct SoCVendorInfo<R: CpuIdReader> {
5589 read: R,
5590 eax: u32,
5592 ebx: u32,
5593 ecx: u32,
5594 edx: u32,
5595}
5596
5597impl<R: CpuIdReader> SoCVendorInfo<R> {
5598 pub fn get_soc_vendor_id(&self) -> u16 {
5599 get_bits(self.ebx, 0, 15) as u16
5600 }
5601
5602 pub fn get_project_id(&self) -> u32 {
5603 self.ecx
5604 }
5605
5606 pub fn get_stepping_id(&self) -> u32 {
5607 self.edx
5608 }
5609
5610 pub fn get_vendor_brand(&self) -> Option<SoCVendorBrand> {
5611 if self.eax >= 3 {
5613 let r1 = self.read.cpuid2(EAX_SOC_VENDOR_INFO, 1);
5614 let r2 = self.read.cpuid2(EAX_SOC_VENDOR_INFO, 2);
5615 let r3 = self.read.cpuid2(EAX_SOC_VENDOR_INFO, 3);
5616 Some(SoCVendorBrand { data: [r1, r2, r3] })
5617 } else {
5618 None
5619 }
5620 }
5621
5622 pub fn get_vendor_attributes(&self) -> Option<SoCVendorAttributesIter<R>> {
5623 if self.eax > 3 {
5624 Some(SoCVendorAttributesIter {
5625 read: self.read.clone(),
5626 count: self.eax,
5627 current: 3,
5628 })
5629 } else {
5630 None
5631 }
5632 }
5633}
5634
5635impl<R: CpuIdReader> fmt::Debug for SoCVendorInfo<R> {
5636 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
5637 f.debug_struct("SoCVendorInfo")
5638 .field("soc_vendor_id", &self.get_soc_vendor_id())
5639 .field("project_id", &self.get_project_id())
5640 .field("stepping_id", &self.get_stepping_id())
5641 .field("vendor_brand", &self.get_vendor_brand())
5642 .field("vendor_attributes", &self.get_vendor_attributes())
5643 .finish()
5644 }
5645}
5646
5647pub struct SoCVendorAttributesIter<R: CpuIdReader> {
5649 read: R,
5650 count: u32,
5651 current: u32,
5652}
5653
5654impl<R: CpuIdReader> fmt::Debug for SoCVendorAttributesIter<R> {
5655 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
5656 f.debug_struct("SocVendorAttributesIter")
5657 .field("count", &self.count)
5658 .field("current", &self.current)
5659 .finish()
5660 }
5661}
5662
5663impl<R: CpuIdReader> Iterator for SoCVendorAttributesIter<R> {
5664 type Item = CpuIdResult;
5665
5666 fn next(&mut self) -> Option<CpuIdResult> {
5668 if self.current > self.count {
5669 return None;
5670 }
5671 self.count += 1;
5672 Some(self.read.cpuid2(EAX_SOC_VENDOR_INFO, self.count))
5673 }
5674}
5675
5676#[derive(Debug, PartialEq, Eq)]
5678#[repr(C)]
5679pub struct SoCVendorBrand {
5680 data: [CpuIdResult; 3],
5681}
5682
5683impl SoCVendorBrand {
5684 pub fn as_str(&self) -> &str {
5686 let brand_string_start = self as *const SoCVendorBrand as *const u8;
5687 let slice = unsafe {
5688 slice::from_raw_parts(brand_string_start, size_of::<SoCVendorBrand>())
5690 };
5691 str::from_utf8(slice).unwrap_or("InvalidSoCVendorString")
5692 }
5693
5694 #[deprecated(
5695 since = "10.0.0",
5696 note = "Use idiomatic function name `as_str` instead"
5697 )]
5698 pub fn as_string(&self) -> &str {
5699 self.as_str()
5700 }
5701}
5702
5703impl fmt::Display for SoCVendorBrand {
5704 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
5705 write!(f, "{}", self.as_str())
5706 }
5707}
5708
5709pub struct HypervisorInfo<R: CpuIdReader> {
5714 read: R,
5715 res: CpuIdResult,
5716}
5717
5718impl<R: CpuIdReader> fmt::Debug for HypervisorInfo<R> {
5719 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
5720 f.debug_struct("HypervisorInfo")
5721 .field("identify", &self.identify())
5722 .field("tsc_frequency", &self.tsc_frequency())
5723 .field("apic_frequency", &self.apic_frequency())
5724 .finish()
5725 }
5726}
5727
5728#[derive(Debug, Eq, PartialEq)]
5730pub enum Hypervisor {
5731 Xen,
5732 VMware,
5733 HyperV,
5734 KVM,
5735 QEMU,
5738 Bhyve,
5739 QNX,
5740 ACRN,
5741 Unknown(u32, u32, u32),
5742}
5743
5744impl<R: CpuIdReader> HypervisorInfo<R> {
5745 pub fn identify(&self) -> Hypervisor {
5756 match (self.res.ebx, self.res.ecx, self.res.edx) {
5757 (0x61774d56, 0x4d566572, 0x65726177) => Hypervisor::VMware,
5759 (0x566e6558, 0x65584d4d, 0x4d4d566e) => Hypervisor::Xen,
5761 (0x7263694d, 0x666f736f, 0x76482074) => Hypervisor::HyperV,
5763 (0x4b4d564b, 0x564b4d56, 0x0000004d) => Hypervisor::KVM,
5765 (0x54474354, 0x43544743, 0x47435447) => Hypervisor::QEMU,
5768 (0x76796862, 0x68622065, 0x20657679) => Hypervisor::Bhyve,
5771 (0x56794842, 0x48422045, 0x20455679) => Hypervisor::Bhyve,
5775 (0x51584e51, 0x53424d56, 0x00004751) => Hypervisor::QNX,
5779 (0x4e524341, 0x4e524341, 0x4e524341) => Hypervisor::ACRN,
5781 (ebx, ecx, edx) => Hypervisor::Unknown(ebx, ecx, edx),
5782 }
5783 }
5784
5785 pub fn tsc_frequency(&self) -> Option<u32> {
5787 if self.res.eax >= 0x40000010 {
5790 let virt_tinfo = self.read.cpuid2(0x40000010, 0);
5791 Some(virt_tinfo.eax)
5792 } else {
5793 None
5794 }
5795 }
5796
5797 pub fn apic_frequency(&self) -> Option<u32> {
5799 if self.res.eax >= 0x40000010 {
5801 let virt_tinfo = self.read.cpuid2(0x40000010, 0);
5802 Some(virt_tinfo.ebx)
5803 } else {
5804 None
5805 }
5806 }
5807}
5808
5809#[cfg(doctest)]
5810mod test_readme {
5811 macro_rules! external_doc_test {
5812 ($x:expr) => {
5813 #[doc = $x]
5814 extern "C" {}
5815 };
5816 }
5817
5818 external_doc_test!(include_str!("../README.md"));
5819}