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]
3529 pub const fn has_avx512vbmi(&self) -> bool {
3530 self.ecx.contains(ExtendedFeaturesEcx::AVX512VBMI)
3531 }
3532
3533 #[inline]
3538 pub const fn has_umip(&self) -> bool {
3539 self.ecx.contains(ExtendedFeaturesEcx::UMIP)
3540 }
3541
3542 #[inline]
3547 pub const fn has_pku(&self) -> bool {
3548 self.ecx.contains(ExtendedFeaturesEcx::PKU)
3549 }
3550
3551 #[inline]
3557 pub const fn has_ospke(&self) -> bool {
3558 self.ecx.contains(ExtendedFeaturesEcx::OSPKE)
3559 }
3560
3561 #[inline]
3565 pub const fn has_waitpkg(&self) -> bool {
3566 self.ecx.contains(ExtendedFeaturesEcx::WAITPKG)
3567 }
3568
3569 #[deprecated(since = "11.4.0", note = "Please use `has_avx512vbmi2` instead")]
3573 #[inline]
3574 pub const fn has_av512vbmi2(&self) -> bool {
3575 self.ecx.contains(ExtendedFeaturesEcx::AVX512VBMI2)
3576 }
3577
3578 #[inline]
3582 pub const fn has_avx512vbmi2(&self) -> bool {
3583 self.ecx.contains(ExtendedFeaturesEcx::AVX512VBMI2)
3584 }
3585
3586 #[inline]
3592 pub const fn has_cet_ss(&self) -> bool {
3593 self.ecx.contains(ExtendedFeaturesEcx::CETSS)
3594 }
3595
3596 #[inline]
3600 pub const fn has_gfni(&self) -> bool {
3601 self.ecx.contains(ExtendedFeaturesEcx::GFNI)
3602 }
3603
3604 #[inline]
3608 pub const fn has_vaes(&self) -> bool {
3609 self.ecx.contains(ExtendedFeaturesEcx::VAES)
3610 }
3611
3612 #[inline]
3616 pub const fn has_vpclmulqdq(&self) -> bool {
3617 self.ecx.contains(ExtendedFeaturesEcx::VPCLMULQDQ)
3618 }
3619
3620 #[inline]
3625 pub const fn has_avx512vnni(&self) -> bool {
3626 self.ecx.contains(ExtendedFeaturesEcx::AVX512VNNI)
3627 }
3628
3629 #[inline]
3633 pub const fn has_avx512bitalg(&self) -> bool {
3634 self.ecx.contains(ExtendedFeaturesEcx::AVX512BITALG)
3635 }
3636
3637 #[inline]
3642 pub const fn has_tme_en(&self) -> bool {
3643 self.ecx.contains(ExtendedFeaturesEcx::TMEEN)
3644 }
3645
3646 #[inline]
3650 pub const fn has_avx512vpopcntdq(&self) -> bool {
3651 self.ecx.contains(ExtendedFeaturesEcx::AVX512VPOPCNTDQ)
3652 }
3653
3654 #[inline]
3659 pub const fn has_la57(&self) -> bool {
3660 self.ecx.contains(ExtendedFeaturesEcx::LA57)
3661 }
3662
3663 #[inline]
3673 pub const fn has_rdpid(&self) -> bool {
3674 self.ecx.contains(ExtendedFeaturesEcx::RDPID)
3675 }
3676
3677 #[inline]
3682 pub const fn has_sgx_lc(&self) -> bool {
3683 self.ecx.contains(ExtendedFeaturesEcx::SGX_LC)
3684 }
3685
3686 #[inline]
3691 pub fn mawau_value(&self) -> u8 {
3692 get_bits(self.ecx.bits(), 17, 21) as u8
3693 }
3694
3695 #[inline]
3700 pub const fn has_avx512_4vnniw(&self) -> bool {
3701 self.edx.contains(ExtendedFeaturesEdx::AVX512_4VNNIW)
3702 }
3703
3704 #[inline]
3709 pub const fn has_avx512_4fmaps(&self) -> bool {
3710 self.edx.contains(ExtendedFeaturesEdx::AVX512_4FMAPS)
3711 }
3712
3713 #[inline]
3718 pub const fn has_avx512_vp2intersect(&self) -> bool {
3719 self.edx.contains(ExtendedFeaturesEdx::AVX512_VP2INTERSECT)
3720 }
3721
3722 #[inline]
3727 pub const fn has_amx_bf16(&self) -> bool {
3728 self.edx.contains(ExtendedFeaturesEdx::AMX_BF16)
3729 }
3730
3731 #[inline]
3736 pub const fn has_avx512_fp16(&self) -> bool {
3737 self.edx.contains(ExtendedFeaturesEdx::AVX512_FP16)
3738 }
3739
3740 #[inline]
3745 pub const fn has_amx_tile(&self) -> bool {
3746 self.edx.contains(ExtendedFeaturesEdx::AMX_TILE)
3747 }
3748
3749 #[inline]
3754 pub const fn has_amx_int8(&self) -> bool {
3755 self.edx.contains(ExtendedFeaturesEdx::AMX_INT8)
3756 }
3757
3758 #[inline]
3763 pub const fn has_avx_vnni(&self) -> bool {
3764 self.eax1.contains(ExtendedFeaturesEax1::AVX_VNNI)
3765 }
3766
3767 #[inline]
3772 pub const fn has_avx512_bf16(&self) -> bool {
3773 self.eax1.contains(ExtendedFeaturesEax1::AVX512_BF16)
3774 }
3775
3776 #[inline]
3781 pub const fn has_fzrm(&self) -> bool {
3782 self.eax1.contains(ExtendedFeaturesEax1::FZRM)
3783 }
3784
3785 #[inline]
3790 pub const fn has_fsrs(&self) -> bool {
3791 self.eax1.contains(ExtendedFeaturesEax1::FSRS)
3792 }
3793
3794 #[inline]
3799 pub const fn has_fsrcrs(&self) -> bool {
3800 self.eax1.contains(ExtendedFeaturesEax1::FSRCRS)
3801 }
3802
3803 #[inline]
3808 pub const fn has_hreset(&self) -> bool {
3809 self.eax1.contains(ExtendedFeaturesEax1::HRESET)
3810 }
3811
3812 #[inline]
3817 pub const fn has_cet_sss(&self) -> bool {
3818 self.edx1.contains(ExtendedFeaturesEdx1::CET_SSS)
3819 }
3820}
3821
3822impl Debug for ExtendedFeatures {
3823 fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
3824 f.debug_struct("ExtendedFeatures")
3825 .field("ebx", &self.ebx)
3826 .field("ecx", &self.ecx)
3827 .field("mawau_value", &self.mawau_value())
3828 .finish()
3829 }
3830}
3831
3832bitflags! {
3833 #[repr(transparent)]
3834 #[derive(Debug, Clone, Copy, PartialEq, Eq)]
3835 struct ExtendedFeaturesEbx: u32 {
3836 const FSGSBASE = 1 << 0;
3838 const ADJUST_MSR = 1 << 1;
3840 const SGX = 1 << 2;
3842 const BMI1 = 1 << 3;
3844 const HLE = 1 << 4;
3846 const AVX2 = 1 << 5;
3848 const FDP = 1 << 6;
3850 const SMEP = 1 << 7;
3852 const BMI2 = 1 << 8;
3854 const REP_MOVSB_STOSB = 1 << 9;
3856 const INVPCID = 1 << 10;
3858 const RTM = 1 << 11;
3860 const RDTM = 1 << 12;
3862 const DEPRECATE_FPU_CS_DS = 1 << 13;
3864 const MPX = 1 << 14;
3866 const RDTA = 1 << 15;
3868 const AVX512F = 1 << 16;
3870 const AVX512DQ = 1 << 17;
3872 const RDSEED = 1 << 18;
3874 const ADX = 1 << 19;
3876 const SMAP = 1 << 20;
3878 const AVX512_IFMA = 1 << 21;
3880 const CLFLUSHOPT = 1 << 23;
3883 const CLWB = 1 << 24;
3885 const PROCESSOR_TRACE = 1 << 25;
3887 const AVX512PF = 1 << 26;
3889 const AVX512ER = 1 << 27;
3891 const AVX512CD = 1 << 28;
3893 const SHA = 1 << 29;
3895 const AVX512BW = 1 << 30;
3897 const AVX512VL = 1 << 31;
3899 }
3900}
3901
3902bitflags! {
3903 #[repr(transparent)]
3904 #[derive(Debug, Clone, Copy, PartialEq, Eq)]
3905 struct ExtendedFeaturesEcx: u32 {
3906 const PREFETCHWT1 = 1 << 0;
3908 const AVX512VBMI = 1 << 1;
3910 const UMIP = 1 << 2;
3912 const PKU = 1 << 3;
3914 const OSPKE = 1 << 4;
3916 const WAITPKG = 1 << 5;
3918 const AVX512VBMI2 = 1 << 6;
3920 const CETSS = 1 << 7;
3924 const GFNI = 1 << 8;
3926 const VAES = 1 << 9;
3928 const VPCLMULQDQ = 1 << 10;
3930 const AVX512VNNI = 1 << 11;
3932 const AVX512BITALG = 1 << 12;
3934 const TMEEN = 1 << 13;
3937 const AVX512VPOPCNTDQ = 1 << 14;
3939
3940 const LA57 = 1 << 16;
3944
3945 const RDPID = 1 << 22;
3949
3950 const SGX_LC = 1 << 30;
3954 }
3955}
3956
3957bitflags! {
3958 #[repr(transparent)]
3959 #[derive(Debug, Clone, Copy, PartialEq, Eq)]
3960 struct ExtendedFeaturesEdx: u32 {
3961 const AVX512_4VNNIW = 1 << 2;
3963 const AVX512_4FMAPS = 1 << 3;
3965 const AVX512_VP2INTERSECT = 1 << 8;
3967 const AMX_BF16 = 1 << 22;
3969 const AVX512_FP16 = 1 << 23;
3971 const AMX_TILE = 1 << 24;
3973 const AMX_INT8 = 1 << 25;
3975 }
3976}
3977
3978bitflags! {
3979 #[repr(transparent)]
3980 #[derive(Debug, Clone, Copy, PartialEq, Eq)]
3981 struct ExtendedFeaturesEax1: u32 {
3982 const AVX_VNNI = 1 << 4;
3985 const AVX512_BF16 = 1 << 5;
3987 const FZRM = 1 << 10;
3989 const FSRS = 1 << 11;
3991 const FSRCRS = 1 << 12;
3993 const HRESET = 1 << 22;
3995 }
3996}
3997
3998bitflags! {
3999 #[repr(transparent)]
4000 #[derive(Debug, Clone, Copy, PartialEq, Eq)]
4001 struct ExtendedFeaturesEdx1: u32 {
4002 const CET_SSS = 1 << 18;
4005 }
4006}
4007
4008pub struct DirectCacheAccessInfo {
4013 eax: u32,
4014}
4015
4016impl DirectCacheAccessInfo {
4017 pub fn get_dca_cap_value(&self) -> u32 {
4019 self.eax
4020 }
4021}
4022
4023impl Debug for DirectCacheAccessInfo {
4024 fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
4025 f.debug_struct("DirectCacheAccessInfo")
4026 .field("dca_cap_value", &self.get_dca_cap_value())
4027 .finish()
4028 }
4029}
4030
4031pub struct PerformanceMonitoringInfo {
4036 eax: u32,
4037 ebx: PerformanceMonitoringFeaturesEbx,
4038 _ecx: u32,
4039 edx: u32,
4040}
4041
4042impl PerformanceMonitoringInfo {
4043 pub fn version_id(&self) -> u8 {
4045 get_bits(self.eax, 0, 7) as u8
4046 }
4047
4048 pub fn number_of_counters(&self) -> u8 {
4050 get_bits(self.eax, 8, 15) as u8
4051 }
4052
4053 pub fn counter_bit_width(&self) -> u8 {
4055 get_bits(self.eax, 16, 23) as u8
4056 }
4057
4058 pub fn ebx_length(&self) -> u8 {
4060 get_bits(self.eax, 24, 31) as u8
4061 }
4062
4063 pub fn fixed_function_counters(&self) -> u8 {
4065 get_bits(self.edx, 0, 4) as u8
4066 }
4067
4068 pub fn fixed_function_counters_bit_width(&self) -> u8 {
4070 get_bits(self.edx, 5, 12) as u8
4071 }
4072
4073 check_bit_fn!(
4074 doc = "AnyThread deprecation",
4075 has_any_thread_deprecation,
4076 edx,
4077 15
4078 );
4079
4080 check_flag!(
4081 doc = "Core cycle event not available if 1.",
4082 is_core_cyc_ev_unavailable,
4083 ebx,
4084 PerformanceMonitoringFeaturesEbx::CORE_CYC_EV_UNAVAILABLE
4085 );
4086
4087 check_flag!(
4088 doc = "Instruction retired event not available if 1.",
4089 is_inst_ret_ev_unavailable,
4090 ebx,
4091 PerformanceMonitoringFeaturesEbx::INST_RET_EV_UNAVAILABLE
4092 );
4093
4094 check_flag!(
4095 doc = "Reference cycles event not available if 1.",
4096 is_ref_cycle_ev_unavailable,
4097 ebx,
4098 PerformanceMonitoringFeaturesEbx::REF_CYC_EV_UNAVAILABLE
4099 );
4100
4101 check_flag!(
4102 doc = "Last-level cache reference event not available if 1.",
4103 is_cache_ref_ev_unavailable,
4104 ebx,
4105 PerformanceMonitoringFeaturesEbx::CACHE_REF_EV_UNAVAILABLE
4106 );
4107
4108 check_flag!(
4109 doc = "Last-level cache misses event not available if 1.",
4110 is_ll_cache_miss_ev_unavailable,
4111 ebx,
4112 PerformanceMonitoringFeaturesEbx::LL_CACHE_MISS_EV_UNAVAILABLE
4113 );
4114
4115 check_flag!(
4116 doc = "Branch instruction retired event not available if 1.",
4117 is_branch_inst_ret_ev_unavailable,
4118 ebx,
4119 PerformanceMonitoringFeaturesEbx::BRANCH_INST_RET_EV_UNAVAILABLE
4120 );
4121
4122 check_flag!(
4123 doc = "Branch mispredict retired event not available if 1.",
4124 is_branch_midpred_ev_unavailable,
4125 ebx,
4126 PerformanceMonitoringFeaturesEbx::BRANCH_MISPRED_EV_UNAVAILABLE
4127 );
4128}
4129
4130impl Debug for PerformanceMonitoringInfo {
4131 fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
4132 f.debug_struct("PerformanceMonitoringInfo")
4133 .field("version_id", &self.version_id())
4134 .field("number_of_counters", &self.number_of_counters())
4135 .field("counter_bit_width", &self.counter_bit_width())
4136 .field("ebx_length", &self.ebx_length())
4137 .field("fixed_function_counters", &self.fixed_function_counters())
4138 .field(
4139 "fixed_function_counters_bit_width",
4140 &self.fixed_function_counters_bit_width(),
4141 )
4142 .finish()
4143 }
4144}
4145
4146bitflags! {
4147 #[repr(transparent)]
4148 #[derive(Debug, Clone, Copy, PartialEq, Eq)]
4149 struct PerformanceMonitoringFeaturesEbx: u32 {
4150 const CORE_CYC_EV_UNAVAILABLE = 1 << 0;
4152 const INST_RET_EV_UNAVAILABLE = 1 << 1;
4154 const REF_CYC_EV_UNAVAILABLE = 1 << 2;
4156 const CACHE_REF_EV_UNAVAILABLE = 1 << 3;
4158 const LL_CACHE_MISS_EV_UNAVAILABLE = 1 << 4;
4160 const BRANCH_INST_RET_EV_UNAVAILABLE = 1 << 5;
4162 const BRANCH_MISPRED_EV_UNAVAILABLE = 1 << 6;
4164 }
4165}
4166
4167#[derive(Clone)]
4176pub struct ExtendedTopologyIter<R: CpuIdReader> {
4177 read: R,
4178 level: u32,
4179 is_v2: bool,
4180}
4181
4182#[derive(PartialEq, Eq)]
4186pub struct ExtendedTopologyLevel {
4187 eax: u32,
4188 ebx: u32,
4189 ecx: u32,
4190 edx: u32,
4191}
4192
4193impl fmt::Debug for ExtendedTopologyLevel {
4194 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
4195 f.debug_struct("ExtendedTopologyLevel")
4196 .field("processors", &self.processors())
4197 .field("number", &self.level_number())
4198 .field("type", &self.level_type())
4199 .field("x2apic_id", &self.x2apic_id())
4200 .field("next_apic_id", &self.shift_right_for_next_apic_id())
4201 .finish()
4202 }
4203}
4204
4205impl ExtendedTopologyLevel {
4206 pub fn processors(&self) -> u16 {
4209 get_bits(self.ebx, 0, 15) as u16
4210 }
4211
4212 pub fn level_number(&self) -> u8 {
4214 get_bits(self.ecx, 0, 7) as u8
4215 }
4216
4217 pub fn level_type(&self) -> TopologyType {
4219 match get_bits(self.ecx, 8, 15) {
4220 0 => TopologyType::Invalid,
4221 1 => TopologyType::SMT,
4222 2 => TopologyType::Core,
4223 3 => TopologyType::Module,
4224 4 => TopologyType::Tile,
4225 5 => TopologyType::Die,
4226 _ => unreachable!(),
4227 }
4228 }
4229
4230 pub fn x2apic_id(&self) -> u32 {
4232 self.edx
4233 }
4234
4235 pub fn shift_right_for_next_apic_id(&self) -> u32 {
4238 get_bits(self.eax, 0, 4)
4239 }
4240}
4241
4242#[derive(PartialEq, Eq, Debug)]
4244pub enum TopologyType {
4245 Invalid = 0,
4246 SMT = 1,
4248 Core = 2,
4249 Module = 3,
4250 Tile = 4,
4251 Die = 5,
4252}
4253
4254impl fmt::Display for TopologyType {
4255 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
4256 let data = match self {
4257 TopologyType::Invalid => "Invalid",
4258 TopologyType::SMT => "SMT",
4259 TopologyType::Core => "Core",
4260 TopologyType::Module => "Module",
4261 TopologyType::Tile => "Tile",
4262 TopologyType::Die => "Die",
4263 };
4264
4265 f.write_str(data)
4266 }
4267}
4268
4269impl<R: CpuIdReader> Iterator for ExtendedTopologyIter<R> {
4270 type Item = ExtendedTopologyLevel;
4271
4272 fn next(&mut self) -> Option<ExtendedTopologyLevel> {
4273 let res = if self.is_v2 {
4274 self.read.cpuid2(EAX_EXTENDED_TOPOLOGY_INFO_V2, self.level)
4275 } else {
4276 self.read.cpuid2(EAX_EXTENDED_TOPOLOGY_INFO, self.level)
4277 };
4278 self.level += 1;
4279
4280 let et = ExtendedTopologyLevel {
4281 eax: res.eax,
4282 ebx: res.ebx,
4283 ecx: res.ecx,
4284 edx: res.edx,
4285 };
4286
4287 match et.level_type() {
4288 TopologyType::Invalid => None,
4289 _ => Some(et),
4290 }
4291 }
4292}
4293
4294impl<R: CpuIdReader> Debug for ExtendedTopologyIter<R> {
4295 fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
4296 let mut debug = f.debug_list();
4297 self.clone().for_each(|ref item| {
4298 debug.entry(item);
4299 });
4300 debug.finish()
4301 }
4302}
4303
4304bitflags! {
4305 #[repr(transparent)]
4306 #[derive(Debug, Clone, Copy, PartialEq, Eq)]
4307 struct ExtendedStateInfoXCR0Flags: u32 {
4308 const LEGACY_X87 = 1 << 0;
4310
4311 const SSE128 = 1 << 1;
4313
4314 const AVX256 = 1 << 2;
4316
4317 const MPX_BNDREGS = 1 << 3;
4319
4320 const MPX_BNDCSR = 1 << 4;
4322
4323 const AVX512_OPMASK = 1 << 5;
4325
4326 const AVX512_ZMM_HI256 = 1 << 6;
4328
4329 const AVX512_ZMM_HI16 = 1 << 7;
4331
4332 const PKRU = 1 << 9;
4334
4335 const IA32_XSS_HDC = 1 << 13;
4337
4338 const AMX_TILECFG = 1 << 17;
4340
4341 const AMX_TILEDATA = 1 << 18;
4343 }
4344}
4345
4346bitflags! {
4347 #[repr(transparent)]
4348 #[derive(Debug, Clone, Copy, PartialEq, Eq)]
4349 struct ExtendedStateInfoXSSFlags: u32 {
4350 const PT = 1 << 8;
4352
4353 const PASID = 1 << 10;
4355
4356 const CET_USER = 1 << 11;
4358
4359 const CET_SUPERVISOR = 1 << 12;
4361
4362 const HDC = 1 << 13;
4364
4365 const UINTR = 1 << 14;
4367
4368 const LBR = 1 << 15;
4370
4371 const HWP = 1 << 16;
4373 }
4374}
4375
4376pub struct ExtendedStateInfo<R: CpuIdReader> {
4381 read: R,
4382 eax: ExtendedStateInfoXCR0Flags,
4383 ebx: u32,
4384 ecx: u32,
4385 _edx: u32,
4386 eax1: u32,
4387 ebx1: u32,
4388 ecx1: ExtendedStateInfoXSSFlags,
4389 _edx1: u32,
4390}
4391
4392impl<F: CpuIdReader> ExtendedStateInfo<F> {
4393 check_flag!(
4394 doc = "Support for legacy x87 in XCR0.",
4395 xcr0_supports_legacy_x87,
4396 eax,
4397 ExtendedStateInfoXCR0Flags::LEGACY_X87
4398 );
4399
4400 check_flag!(
4401 doc = "Support for SSE 128-bit in XCR0.",
4402 xcr0_supports_sse_128,
4403 eax,
4404 ExtendedStateInfoXCR0Flags::SSE128
4405 );
4406
4407 check_flag!(
4408 doc = "Support for AVX 256-bit in XCR0.",
4409 xcr0_supports_avx_256,
4410 eax,
4411 ExtendedStateInfoXCR0Flags::AVX256
4412 );
4413
4414 check_flag!(
4415 doc = "Support for MPX BNDREGS in XCR0.",
4416 xcr0_supports_mpx_bndregs,
4417 eax,
4418 ExtendedStateInfoXCR0Flags::MPX_BNDREGS
4419 );
4420
4421 check_flag!(
4422 doc = "Support for MPX BNDCSR in XCR0.",
4423 xcr0_supports_mpx_bndcsr,
4424 eax,
4425 ExtendedStateInfoXCR0Flags::MPX_BNDCSR
4426 );
4427
4428 check_flag!(
4429 doc = "Support for AVX512 OPMASK in XCR0.",
4430 xcr0_supports_avx512_opmask,
4431 eax,
4432 ExtendedStateInfoXCR0Flags::AVX512_OPMASK
4433 );
4434
4435 check_flag!(
4436 doc = "Support for AVX512 ZMM Hi256 XCR0.",
4437 xcr0_supports_avx512_zmm_hi256,
4438 eax,
4439 ExtendedStateInfoXCR0Flags::AVX512_ZMM_HI256
4440 );
4441
4442 check_flag!(
4443 doc = "Support for AVX512 ZMM Hi16 in XCR0.",
4444 xcr0_supports_avx512_zmm_hi16,
4445 eax,
4446 ExtendedStateInfoXCR0Flags::AVX512_ZMM_HI16
4447 );
4448
4449 check_flag!(
4450 doc = "Support for PKRU in XCR0.",
4451 xcr0_supports_pkru,
4452 eax,
4453 ExtendedStateInfoXCR0Flags::PKRU
4454 );
4455
4456 check_flag!(
4457 doc = "Support for PT in IA32_XSS.",
4458 ia32_xss_supports_pt,
4459 ecx1,
4460 ExtendedStateInfoXSSFlags::PT
4461 );
4462
4463 check_flag!(
4464 doc = "Support for HDC in IA32_XSS.",
4465 ia32_xss_supports_hdc,
4466 ecx1,
4467 ExtendedStateInfoXSSFlags::HDC
4468 );
4469
4470 pub fn xsave_area_size_enabled_features(&self) -> u32 {
4474 self.ebx
4475 }
4476
4477 pub fn xsave_area_size_supported_features(&self) -> u32 {
4481 self.ecx
4482 }
4483
4484 pub fn has_xsaveopt(&self) -> bool {
4486 self.eax1 & 0x1 > 0
4487 }
4488
4489 pub fn has_xsavec(&self) -> bool {
4491 self.eax1 & 0b10 > 0
4492 }
4493
4494 pub fn has_xgetbv(&self) -> bool {
4496 self.eax1 & 0b100 > 0
4497 }
4498
4499 pub fn has_xsaves_xrstors(&self) -> bool {
4501 self.eax1 & 0b1000 > 0
4502 }
4503
4504 pub fn xsave_size(&self) -> u32 {
4506 self.ebx1
4507 }
4508
4509 pub fn iter(&self) -> ExtendedStateIter<F> {
4511 ExtendedStateIter {
4512 read: self.read.clone(),
4513 level: 1,
4514 supported_xcr0: self.eax.bits(),
4515 supported_xss: self.ecx1.bits(),
4516 }
4517 }
4518}
4519
4520impl<R: CpuIdReader> Debug for ExtendedStateInfo<R> {
4521 fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
4522 f.debug_struct("ExtendedStateInfo")
4523 .field("eax", &self.eax)
4524 .field("ecx1", &self.ecx1)
4525 .field(
4526 "xsave_area_size_enabled_features",
4527 &self.xsave_area_size_enabled_features(),
4528 )
4529 .field(
4530 "xsave_area_size_supported_features",
4531 &self.xsave_area_size_supported_features(),
4532 )
4533 .field("has_xsaveopt", &self.has_xsaveopt())
4534 .field("has_xsavec", &self.has_xsavec())
4535 .field("has_xgetbv", &self.has_xgetbv())
4536 .field("has_xsaves_xrstors", &self.has_xsaves_xrstors())
4537 .field("xsave_size", &self.xsave_size())
4538 .field("extended_state_iter", &self.iter())
4539 .finish()
4540 }
4541}
4542
4543#[derive(Clone)]
4545pub struct ExtendedStateIter<R: CpuIdReader> {
4546 read: R,
4547 level: u32,
4548 supported_xcr0: u32,
4549 supported_xss: u32,
4550}
4551
4552impl<R: CpuIdReader> Iterator for ExtendedStateIter<R> {
4559 type Item = ExtendedState;
4560
4561 fn next(&mut self) -> Option<ExtendedState> {
4562 self.level += 1;
4563 if self.level > 31 {
4564 return None;
4565 }
4566
4567 let bit = 1 << self.level;
4568 if (self.supported_xcr0 & bit > 0) || (self.supported_xss & bit > 0) {
4569 let res = self.read.cpuid2(EAX_EXTENDED_STATE_INFO, self.level);
4570 return Some(ExtendedState {
4571 subleaf: self.level,
4572 eax: res.eax,
4573 ebx: res.ebx,
4574 ecx: res.ecx,
4575 });
4576 }
4577
4578 self.next()
4579 }
4580}
4581
4582impl<R: CpuIdReader> Debug for ExtendedStateIter<R> {
4583 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
4584 let mut debug = f.debug_list();
4585 self.clone().for_each(|ref item| {
4586 debug.entry(item);
4587 });
4588 debug.finish()
4589 }
4590}
4591
4592#[derive(PartialEq, Eq, Debug)]
4594#[repr(u32)]
4595pub enum ExtendedRegisterType {
4596 Avx,
4597 MpxBndregs,
4598 MpxBndcsr,
4599 Avx512Opmask,
4600 Avx512ZmmHi256,
4601 Avx512ZmmHi16,
4602 Pt,
4603 Pkru,
4604 Hdc,
4605 Unknown(u32),
4606}
4607
4608impl From<u32> for ExtendedRegisterType {
4609 fn from(value: u32) -> ExtendedRegisterType {
4610 match value {
4611 0x2 => ExtendedRegisterType::Avx,
4612 0x3 => ExtendedRegisterType::MpxBndregs,
4613 0x4 => ExtendedRegisterType::MpxBndcsr,
4614 0x5 => ExtendedRegisterType::Avx512Opmask,
4615 0x6 => ExtendedRegisterType::Avx512ZmmHi256,
4616 0x7 => ExtendedRegisterType::Avx512ZmmHi16,
4617 0x8 => ExtendedRegisterType::Pt,
4618 0x9 => ExtendedRegisterType::Pkru,
4619 0xd => ExtendedRegisterType::Hdc,
4620 x => ExtendedRegisterType::Unknown(x),
4621 }
4622 }
4623}
4624
4625impl fmt::Display for ExtendedRegisterType {
4626 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
4627 let data = match self {
4628 ExtendedRegisterType::Avx => "AVX/YMM",
4629 ExtendedRegisterType::MpxBndregs => "MPX BNDREGS",
4630 ExtendedRegisterType::MpxBndcsr => "MPX BNDCSR",
4631 ExtendedRegisterType::Avx512Opmask => "AVX-512 opmask",
4632 ExtendedRegisterType::Avx512ZmmHi256 => "AVX-512 ZMM_Hi256",
4633 ExtendedRegisterType::Avx512ZmmHi16 => "AVX-512 Hi16_ZMM",
4634 ExtendedRegisterType::Pkru => "PKRU",
4635 ExtendedRegisterType::Pt => "PT",
4636 ExtendedRegisterType::Hdc => "HDC",
4637 ExtendedRegisterType::Unknown(t) => {
4638 return write!(f, "Unknown({})", t);
4639 }
4640 };
4641
4642 f.write_str(data)
4643 }
4644}
4645
4646#[derive(PartialEq, Eq, Debug)]
4648pub enum ExtendedRegisterStateLocation {
4649 Xcr0,
4650 Ia32Xss,
4651}
4652
4653impl fmt::Display for ExtendedRegisterStateLocation {
4654 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
4655 let data = match self {
4656 ExtendedRegisterStateLocation::Xcr0 => "XCR0 (user state)",
4657 ExtendedRegisterStateLocation::Ia32Xss => "IA32_XSS (supervisor state)",
4658 };
4659
4660 f.write_str(data)
4661 }
4662}
4663
4664pub struct ExtendedState {
4666 pub subleaf: u32,
4667 eax: u32,
4668 ebx: u32,
4669 ecx: u32,
4670}
4671
4672impl ExtendedState {
4673 pub fn register(&self) -> ExtendedRegisterType {
4675 self.subleaf.into()
4676 }
4677
4678 pub fn size(&self) -> u32 {
4682 self.eax
4683 }
4684
4685 pub fn offset(&self) -> u32 {
4688 self.ebx
4689 }
4690
4691 pub fn location(&self) -> ExtendedRegisterStateLocation {
4692 if self.is_in_xcr0() {
4693 ExtendedRegisterStateLocation::Xcr0
4694 } else {
4695 ExtendedRegisterStateLocation::Ia32Xss
4696 }
4697 }
4698
4699 pub fn is_in_ia32_xss(&self) -> bool {
4705 self.ecx & 0b1 > 0
4706 }
4707
4708 pub fn is_in_xcr0(&self) -> bool {
4713 self.ecx & 0b1 == 0
4714 }
4715
4716 pub fn is_compacted_format(&self) -> bool {
4721 self.ecx & 0b10 > 0
4722 }
4723}
4724
4725impl Debug for ExtendedState {
4726 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
4727 f.debug_struct("ExtendedState")
4728 .field("size", &self.size())
4729 .field("offset", &self.offset())
4730 .field("is_in_ia32_xss", &self.is_in_ia32_xss())
4731 .field("is_in_xcr0", &self.is_in_xcr0())
4732 .field("is_compacted_format", &self.is_compacted_format())
4733 .finish()
4734 }
4735}
4736
4737pub struct RdtMonitoringInfo<R: CpuIdReader> {
4743 read: R,
4744 ebx: u32,
4745 edx: u32,
4746}
4747
4748impl<R: CpuIdReader> RdtMonitoringInfo<R> {
4749 pub fn rmid_range(&self) -> u32 {
4751 self.ebx
4752 }
4753
4754 check_bit_fn!(
4755 doc = "Supports L3 Cache Intel RDT Monitoring.",
4756 has_l3_monitoring,
4757 edx,
4758 1
4759 );
4760
4761 pub fn l3_monitoring(&self) -> Option<L3MonitoringInfo> {
4763 if self.has_l3_monitoring() {
4764 let res = self.read.cpuid2(EAX_RDT_MONITORING, 1);
4765 Some(L3MonitoringInfo {
4766 ebx: res.ebx,
4767 ecx: res.ecx,
4768 edx: res.edx,
4769 })
4770 } else {
4771 None
4772 }
4773 }
4774}
4775
4776impl<R: CpuIdReader> Debug for RdtMonitoringInfo<R> {
4777 fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
4778 f.debug_struct("RdtMonitoringInfo")
4779 .field("rmid_range", &self.rmid_range())
4780 .field("l3_monitoring", &self.l3_monitoring())
4781 .finish()
4782 }
4783}
4784
4785pub struct L3MonitoringInfo {
4787 ebx: u32,
4788 ecx: u32,
4789 edx: u32,
4790}
4791
4792impl L3MonitoringInfo {
4793 pub fn conversion_factor(&self) -> u32 {
4795 self.ebx
4796 }
4797
4798 pub fn maximum_rmid_range(&self) -> u32 {
4800 self.ecx
4801 }
4802
4803 check_bit_fn!(
4804 doc = "Supports occupancy monitoring.",
4805 has_occupancy_monitoring,
4806 edx,
4807 0
4808 );
4809
4810 check_bit_fn!(
4811 doc = "Supports total bandwidth monitoring.",
4812 has_total_bandwidth_monitoring,
4813 edx,
4814 1
4815 );
4816
4817 check_bit_fn!(
4818 doc = "Supports local bandwidth monitoring.",
4819 has_local_bandwidth_monitoring,
4820 edx,
4821 2
4822 );
4823}
4824
4825impl Debug for L3MonitoringInfo {
4826 fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
4827 f.debug_struct("L3MonitoringInfo")
4828 .field("conversion_factor", &self.conversion_factor())
4829 .field("maximum_rmid_range", &self.maximum_rmid_range())
4830 .finish()
4831 }
4832}
4833
4834pub struct RdtAllocationInfo<R: CpuIdReader> {
4839 read: R,
4840 ebx: u32,
4841}
4842
4843impl<R: CpuIdReader> RdtAllocationInfo<R> {
4844 check_bit_fn!(doc = "Supports L3 Cache Allocation.", has_l3_cat, ebx, 1);
4845
4846 check_bit_fn!(doc = "Supports L2 Cache Allocation.", has_l2_cat, ebx, 2);
4847
4848 check_bit_fn!(
4849 doc = "Supports Memory Bandwidth Allocation.",
4850 has_memory_bandwidth_allocation,
4851 ebx,
4852 3
4853 );
4854
4855 pub fn l3_cat(&self) -> Option<L3CatInfo> {
4857 if self.has_l3_cat() {
4858 let res = self.read.cpuid2(EAX_RDT_ALLOCATION, 1);
4859 Some(L3CatInfo {
4860 eax: res.eax,
4861 ebx: res.ebx,
4862 ecx: res.ecx,
4863 edx: res.edx,
4864 })
4865 } else {
4866 None
4867 }
4868 }
4869
4870 pub fn l2_cat(&self) -> Option<L2CatInfo> {
4872 if self.has_l2_cat() {
4873 let res = self.read.cpuid2(EAX_RDT_ALLOCATION, 2);
4874 Some(L2CatInfo {
4875 eax: res.eax,
4876 ebx: res.ebx,
4877 edx: res.edx,
4878 })
4879 } else {
4880 None
4881 }
4882 }
4883
4884 pub fn memory_bandwidth_allocation(&self) -> Option<MemBwAllocationInfo> {
4886 if self.has_memory_bandwidth_allocation() {
4887 let res = self.read.cpuid2(EAX_RDT_ALLOCATION, 3);
4888 Some(MemBwAllocationInfo {
4889 eax: res.eax,
4890 ecx: res.ecx,
4891 edx: res.edx,
4892 })
4893 } else {
4894 None
4895 }
4896 }
4897}
4898
4899impl<R: CpuIdReader> Debug for RdtAllocationInfo<R> {
4900 fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
4901 f.debug_struct("RdtAllocationInfo")
4902 .field("l3_cat", &self.l3_cat())
4903 .field("l2_cat", &self.l2_cat())
4904 .field(
4905 "memory_bandwidth_allocation",
4906 &self.memory_bandwidth_allocation(),
4907 )
4908 .finish()
4909 }
4910}
4911
4912pub struct L3CatInfo {
4914 eax: u32,
4915 ebx: u32,
4916 ecx: u32,
4917 edx: u32,
4918}
4919
4920impl L3CatInfo {
4921 pub fn capacity_mask_length(&self) -> u8 {
4923 (get_bits(self.eax, 0, 4) + 1) as u8
4924 }
4925
4926 pub fn isolation_bitmap(&self) -> u32 {
4928 self.ebx
4929 }
4930
4931 pub fn highest_cos(&self) -> u16 {
4933 get_bits(self.edx, 0, 15) as u16
4934 }
4935
4936 check_bit_fn!(
4937 doc = "Is Code and Data Prioritization Technology supported?",
4938 has_code_data_prioritization,
4939 ecx,
4940 2
4941 );
4942}
4943
4944impl Debug for L3CatInfo {
4945 fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
4946 f.debug_struct("L3CatInfo")
4947 .field("capacity_mask_length", &self.capacity_mask_length())
4948 .field("isolation_bitmap", &self.isolation_bitmap())
4949 .field("highest_cos", &self.highest_cos())
4950 .finish()
4951 }
4952}
4953
4954#[derive(Eq, PartialEq)]
4956pub struct L2CatInfo {
4957 eax: u32,
4958 ebx: u32,
4959 edx: u32,
4960}
4961
4962impl L2CatInfo {
4963 pub fn capacity_mask_length(&self) -> u8 {
4965 (get_bits(self.eax, 0, 4) + 1) as u8
4966 }
4967
4968 pub fn isolation_bitmap(&self) -> u32 {
4970 self.ebx
4971 }
4972
4973 pub fn highest_cos(&self) -> u16 {
4975 get_bits(self.edx, 0, 15) as u16
4976 }
4977}
4978
4979impl Debug for L2CatInfo {
4980 fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
4981 f.debug_struct("L2CatInfo")
4982 .field("capacity_mask_length", &self.capacity_mask_length())
4983 .field("isolation_bitmap", &self.isolation_bitmap())
4984 .field("highest_cos", &self.highest_cos())
4985 .finish()
4986 }
4987}
4988
4989#[derive(Eq, PartialEq)]
4991pub struct MemBwAllocationInfo {
4992 eax: u32,
4993 ecx: u32,
4994 edx: u32,
4995}
4996
4997impl MemBwAllocationInfo {
4998 pub fn max_hba_throttling(&self) -> u16 {
5000 (get_bits(self.eax, 0, 11) + 1) as u16
5001 }
5002
5003 pub fn highest_cos(&self) -> u16 {
5005 get_bits(self.edx, 0, 15) as u16
5006 }
5007
5008 check_bit_fn!(
5009 doc = "Reports whether the response of the delay values is linear.",
5010 has_linear_response_delay,
5011 ecx,
5012 2
5013 );
5014}
5015
5016impl Debug for MemBwAllocationInfo {
5017 fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
5018 f.debug_struct("MemBwAllocationInfo")
5019 .field("max_hba_throttling", &self.max_hba_throttling())
5020 .field("highest_cos", &self.highest_cos())
5021 .field(
5022 "has_linear_response_delay",
5023 &self.has_linear_response_delay(),
5024 )
5025 .finish()
5026 }
5027}
5028
5029pub struct SgxInfo<R: CpuIdReader> {
5036 read: R,
5037 eax: u32,
5038 ebx: u32,
5039 _ecx: u32,
5040 edx: u32,
5041 eax1: u32,
5042 ebx1: u32,
5043 ecx1: u32,
5044 edx1: u32,
5045}
5046
5047impl<F: CpuIdReader> SgxInfo<F> {
5048 check_bit_fn!(doc = "Has SGX1 support.", has_sgx1, eax, 0);
5049 check_bit_fn!(doc = "Has SGX2 support.", has_sgx2, eax, 1);
5050
5051 check_bit_fn!(
5052 doc = "Supports ENCLV instruction leaves EINCVIRTCHILD, EDECVIRTCHILD, and ESETCONTEXT.",
5053 has_enclv_leaves_einvirtchild_edecvirtchild_esetcontext,
5054 eax,
5055 5
5056 );
5057
5058 check_bit_fn!(
5059 doc = "Supports ENCLS instruction leaves ETRACKC, ERDINFO, ELDBC, and ELDUC.",
5060 has_encls_leaves_etrackc_erdinfo_eldbc_elduc,
5061 eax,
5062 6
5063 );
5064
5065 pub fn miscselect(&self) -> u32 {
5067 self.ebx
5068 }
5069
5070 pub fn max_enclave_size_non_64bit(&self) -> u8 {
5072 get_bits(self.edx, 0, 7) as u8
5073 }
5074
5075 pub fn max_enclave_size_64bit(&self) -> u8 {
5077 get_bits(self.edx, 8, 15) as u8
5078 }
5079
5080 pub fn secs_attributes(&self) -> (u64, u64) {
5082 let lower = self.eax1 as u64 | (self.ebx1 as u64) << 32;
5083 let upper = self.ecx1 as u64 | (self.edx1 as u64) << 32;
5084 (lower, upper)
5085 }
5086 pub fn iter(&self) -> SgxSectionIter<F> {
5088 SgxSectionIter {
5089 read: self.read.clone(),
5090 current: 2,
5091 }
5092 }
5093}
5094
5095impl<R: CpuIdReader> Debug for SgxInfo<R> {
5096 fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
5097 f.debug_struct("SgxInfo")
5098 .field("has_sgx1", &self.has_sgx1())
5099 .field("has_sgx2", &self.has_sgx2())
5100 .field("miscselect", &self.miscselect())
5101 .field(
5102 "max_enclave_size_non_64bit",
5103 &self.max_enclave_size_non_64bit(),
5104 )
5105 .field("max_enclave_size_64bit", &self.max_enclave_size_64bit())
5106 .field(
5107 "has_encls_leaves_etrackc_erdinfo_eldbc_elduc",
5108 &self.has_encls_leaves_etrackc_erdinfo_eldbc_elduc(),
5109 )
5110 .field(
5111 "has_enclv_leaves_einvirtchild_edecvirtchild_esetcontext",
5112 &self.has_enclv_leaves_einvirtchild_edecvirtchild_esetcontext(),
5113 )
5114 .field("sgx_section_iter", &self.iter())
5115 .finish()
5116 }
5117}
5118
5119#[derive(Clone)]
5121pub struct SgxSectionIter<R: CpuIdReader> {
5122 read: R,
5123 current: u32,
5124}
5125
5126impl<R: CpuIdReader> Iterator for SgxSectionIter<R> {
5127 type Item = SgxSectionInfo;
5128
5129 fn next(&mut self) -> Option<SgxSectionInfo> {
5130 let res = self.read.cpuid2(EAX_SGX, self.current);
5131 self.current += 1;
5132 match get_bits(res.eax, 0, 3) {
5133 0b0001 => Some(SgxSectionInfo::Epc(EpcSection {
5134 eax: res.eax,
5135 ebx: res.ebx,
5136 ecx: res.ecx,
5137 edx: res.edx,
5138 })),
5139 _ => None,
5140 }
5141 }
5142}
5143
5144impl<R: CpuIdReader> Debug for SgxSectionIter<R> {
5145 fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
5146 let mut debug = f.debug_list();
5147 self.clone().for_each(|ref item| {
5148 debug.entry(item);
5149 });
5150 debug.finish()
5151 }
5152}
5153
5154#[derive(Debug)]
5158pub enum SgxSectionInfo {
5159 Epc(EpcSection),
5161}
5162
5163#[derive(Debug)]
5165pub struct EpcSection {
5166 eax: u32,
5167 ebx: u32,
5168 ecx: u32,
5169 edx: u32,
5170}
5171
5172impl EpcSection {
5173 pub fn physical_base(&self) -> u64 {
5175 let lower = (get_bits(self.eax, 12, 31) << 12) as u64;
5176 let upper = (get_bits(self.ebx, 0, 19) as u64) << 32;
5177 lower | upper
5178 }
5179
5180 pub fn size(&self) -> u64 {
5182 let lower = (get_bits(self.ecx, 12, 31) << 12) as u64;
5183 let upper = (get_bits(self.edx, 0, 19) as u64) << 32;
5184 lower | upper
5185 }
5186}
5187
5188pub struct ProcessorTraceInfo {
5193 _eax: u32,
5194 ebx: u32,
5195 ecx: u32,
5196 _edx: u32,
5197 leaf1: Option<CpuIdResult>,
5198}
5199
5200impl ProcessorTraceInfo {
5201 check_bit_fn!(
5203 doc = "If true, Indicates that IA32_RTIT_CTL.CR3Filter can be set to 1, and \
5204 that IA32_RTIT_CR3_MATCH MSR can be accessed.",
5205 has_rtit_cr3_match,
5206 ebx,
5207 0
5208 );
5209 check_bit_fn!(
5210 doc = "If true, Indicates support of Configurable PSB and Cycle-Accurate Mode.",
5211 has_configurable_psb_and_cycle_accurate_mode,
5212 ebx,
5213 1
5214 );
5215 check_bit_fn!(
5216 doc = "If true, Indicates support of IP Filtering, TraceStop filtering, and \
5217 preservation of Intel PT MSRs across warm reset.",
5218 has_ip_tracestop_filtering,
5219 ebx,
5220 2
5221 );
5222 check_bit_fn!(
5223 doc = "If true, Indicates support of MTC timing packet and suppression of \
5224 COFI-based packets.",
5225 has_mtc_timing_packet_coefi_suppression,
5226 ebx,
5227 3
5228 );
5229
5230 check_bit_fn!(
5231 doc = "Indicates support of PTWRITE. Writes can set IA32_RTIT_CTL\\[12\\] (PTWEn \
5232 and IA32_RTIT_CTL\\[5\\] (FUPonPTW), and PTWRITE can generate packets",
5233 has_ptwrite,
5234 ebx,
5235 4
5236 );
5237
5238 check_bit_fn!(
5239 doc = "Support of Power Event Trace. Writes can set IA32_RTIT_CTL\\[4\\] (PwrEvtEn) \
5240 enabling Power Event Trace packet generation.",
5241 has_power_event_trace,
5242 ebx,
5243 5
5244 );
5245
5246 check_bit_fn!(
5248 doc = "If true, Tracing can be enabled with IA32_RTIT_CTL.ToPA = 1, hence \
5249 utilizing the ToPA output scheme; IA32_RTIT_OUTPUT_BASE and \
5250 IA32_RTIT_OUTPUT_MASK_PTRS MSRs can be accessed.",
5251 has_topa,
5252 ecx,
5253 0
5254 );
5255 check_bit_fn!(
5256 doc = "If true, ToPA tables can hold any number of output entries, up to the \
5257 maximum allowed by the MaskOrTableOffset field of \
5258 IA32_RTIT_OUTPUT_MASK_PTRS.",
5259 has_topa_maximum_entries,
5260 ecx,
5261 1
5262 );
5263 check_bit_fn!(
5264 doc = "If true, Indicates support of Single-Range Output scheme.",
5265 has_single_range_output_scheme,
5266 ecx,
5267 2
5268 );
5269 check_bit_fn!(
5270 doc = "If true, Indicates support of output to Trace Transport subsystem.",
5271 has_trace_transport_subsystem,
5272 ecx,
5273 3
5274 );
5275 check_bit_fn!(
5276 doc = "If true, Generated packets which contain IP payloads have LIP values, \
5277 which include the CS base component.",
5278 has_lip_with_cs_base,
5279 ecx,
5280 31
5281 );
5282
5283 pub fn configurable_address_ranges(&self) -> u8 {
5285 self.leaf1.map_or(0, |res| get_bits(res.eax, 0, 2) as u8)
5286 }
5287
5288 pub fn supported_mtc_period_encodings(&self) -> u16 {
5290 self.leaf1.map_or(0, |res| get_bits(res.eax, 16, 31) as u16)
5291 }
5292
5293 pub fn supported_cycle_threshold_value_encodings(&self) -> u16 {
5295 self.leaf1.map_or(0, |res| get_bits(res.ebx, 0, 15) as u16)
5296 }
5297
5298 pub fn supported_psb_frequency_encodings(&self) -> u16 {
5300 self.leaf1.map_or(0, |res| get_bits(res.ebx, 16, 31) as u16)
5301 }
5302}
5303
5304impl Debug for ProcessorTraceInfo {
5305 fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
5306 f.debug_struct("ProcessorTraceInfo")
5307 .field(
5308 "configurable_address_ranges",
5309 &self.configurable_address_ranges(),
5310 )
5311 .field(
5312 "supported_mtc_period_encodings",
5313 &self.supported_mtc_period_encodings(),
5314 )
5315 .field(
5316 "supported_cycle_threshold_value_encodings",
5317 &self.supported_cycle_threshold_value_encodings(),
5318 )
5319 .field(
5320 "supported_psb_frequency_encodings",
5321 &self.supported_psb_frequency_encodings(),
5322 )
5323 .finish()
5324 }
5325}
5326
5327pub struct TscInfo {
5332 eax: u32,
5333 ebx: u32,
5334 ecx: u32,
5335}
5336
5337impl fmt::Debug for TscInfo {
5338 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
5339 f.debug_struct("TscInfo")
5340 .field("denominator", &self.denominator())
5341 .field("numerator", &self.numerator())
5342 .field("nominal_frequency", &self.nominal_frequency())
5343 .field("tsc_frequency", &self.tsc_frequency())
5344 .finish()
5345 }
5346}
5347
5348impl TscInfo {
5349 pub fn denominator(&self) -> u32 {
5351 self.eax
5352 }
5353
5354 pub fn numerator(&self) -> u32 {
5358 self.ebx
5359 }
5360
5361 pub fn nominal_frequency(&self) -> u32 {
5365 self.ecx
5366 }
5367
5368 pub fn tsc_frequency(&self) -> Option<u64> {
5370 if self.nominal_frequency() == 0 || self.numerator() == 0 || self.denominator() == 0 {
5373 return None;
5374 }
5375
5376 Some(self.nominal_frequency() as u64 * self.numerator() as u64 / self.denominator() as u64)
5377 }
5378}
5379
5380pub struct ProcessorFrequencyInfo {
5385 eax: u32,
5386 ebx: u32,
5387 ecx: u32,
5388}
5389
5390impl ProcessorFrequencyInfo {
5391 pub fn processor_base_frequency(&self) -> u16 {
5393 get_bits(self.eax, 0, 15) as u16
5394 }
5395
5396 pub fn processor_max_frequency(&self) -> u16 {
5398 get_bits(self.ebx, 0, 15) as u16
5399 }
5400
5401 pub fn bus_frequency(&self) -> u16 {
5403 get_bits(self.ecx, 0, 15) as u16
5404 }
5405}
5406
5407impl fmt::Debug for ProcessorFrequencyInfo {
5408 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
5409 f.debug_struct("ProcessorFrequencyInfo")
5410 .field("processor_base_frequency", &self.processor_base_frequency())
5411 .field("processor_max_frequency", &self.processor_max_frequency())
5412 .field("bus_frequency", &self.bus_frequency())
5413 .finish()
5414 }
5415}
5416
5417#[derive(Clone)]
5422pub struct DatIter<R: CpuIdReader> {
5423 read: R,
5424 current: u32,
5425 count: u32,
5426}
5427
5428impl<R: CpuIdReader> Iterator for DatIter<R> {
5429 type Item = DatInfo;
5430
5431 fn next(&mut self) -> Option<DatInfo> {
5433 loop {
5434 if self.current > self.count {
5436 return None;
5437 }
5438
5439 let res = self
5440 .read
5441 .cpuid2(EAX_DETERMINISTIC_ADDRESS_TRANSLATION_INFO, self.current);
5442 self.current += 1;
5443
5444 if get_bits(res.edx, 0, 4) == 0 {
5446 continue;
5450 }
5451
5452 return Some(DatInfo {
5453 _eax: res.eax,
5454 ebx: res.ebx,
5455 ecx: res.ecx,
5456 edx: res.edx,
5457 });
5458 }
5459 }
5460}
5461
5462impl<R: CpuIdReader> Debug for DatIter<R> {
5463 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
5464 let mut debug = f.debug_list();
5465 self.clone().for_each(|ref item| {
5466 debug.entry(item);
5467 });
5468 debug.finish()
5469 }
5470}
5471
5472pub struct DatInfo {
5474 _eax: u32,
5475 ebx: u32,
5476 ecx: u32,
5477 edx: u32,
5478}
5479
5480impl DatInfo {
5481 check_bit_fn!(
5482 doc = "4K page size entries supported by this structure",
5483 has_4k_entries,
5484 ebx,
5485 0
5486 );
5487
5488 check_bit_fn!(
5489 doc = "2MB page size entries supported by this structure",
5490 has_2mb_entries,
5491 ebx,
5492 1
5493 );
5494
5495 check_bit_fn!(
5496 doc = "4MB page size entries supported by this structure",
5497 has_4mb_entries,
5498 ebx,
5499 2
5500 );
5501
5502 check_bit_fn!(
5503 doc = "1GB page size entries supported by this structure",
5504 has_1gb_entries,
5505 ebx,
5506 3
5507 );
5508
5509 check_bit_fn!(
5510 doc = "Fully associative structure",
5511 is_fully_associative,
5512 edx,
5513 8
5514 );
5515
5516 pub fn partitioning(&self) -> u8 {
5518 get_bits(self.ebx, 8, 10) as u8
5519 }
5520
5521 pub fn ways(&self) -> u16 {
5523 get_bits(self.ebx, 16, 31) as u16
5524 }
5525
5526 pub fn sets(&self) -> u32 {
5528 self.ecx
5529 }
5530
5531 pub fn cache_type(&self) -> DatType {
5533 match get_bits(self.edx, 0, 4) as u8 {
5534 0b00001 => DatType::DataTLB,
5535 0b00010 => DatType::InstructionTLB,
5536 0b00011 => DatType::UnifiedTLB,
5537 0b00000 => DatType::Null, 0b00100 => DatType::LoadOnly,
5539 0b00101 => DatType::StoreOnly,
5540 _ => DatType::Unknown,
5541 }
5542 }
5543
5544 pub fn cache_level(&self) -> u8 {
5546 get_bits(self.edx, 5, 7) as u8
5547 }
5548
5549 pub fn max_addressable_ids(&self) -> u16 {
5551 (get_bits(self.edx, 14, 25) + 1) as u16
5553 }
5554}
5555
5556impl Debug for DatInfo {
5557 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
5558 f.debug_struct("DatInfo")
5559 .field("has_4k_entries", &self.has_4k_entries())
5560 .field("has_2mb_entries", &self.has_2mb_entries())
5561 .field("has_4mb_entries", &self.has_4mb_entries())
5562 .field("has_1gb_entries", &self.has_1gb_entries())
5563 .field("is_fully_associative", &self.is_fully_associative())
5564 .finish()
5565 }
5566}
5567
5568#[derive(Eq, PartialEq, Debug)]
5570pub enum DatType {
5571 Null = 0b00000,
5573 DataTLB = 0b00001,
5574 InstructionTLB = 0b00010,
5575 UnifiedTLB = 0b00011,
5581 LoadOnly = 0b0100,
5582 StoreOnly = 0b0101,
5583 Unknown,
5584}
5585
5586impl fmt::Display for DatType {
5587 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
5588 let t = match self {
5589 DatType::Null => "invalid (0)",
5590 DatType::DataTLB => "Data TLB",
5591 DatType::InstructionTLB => "Instruction TLB",
5592 DatType::UnifiedTLB => "Unified TLB",
5593 DatType::LoadOnly => "Load Only",
5594 DatType::StoreOnly => "Store Only",
5595 DatType::Unknown => "Unknown",
5596 };
5597 f.write_str(t)
5598 }
5599}
5600
5601pub struct SoCVendorInfo<R: CpuIdReader> {
5606 read: R,
5607 eax: u32,
5609 ebx: u32,
5610 ecx: u32,
5611 edx: u32,
5612}
5613
5614impl<R: CpuIdReader> SoCVendorInfo<R> {
5615 pub fn get_soc_vendor_id(&self) -> u16 {
5616 get_bits(self.ebx, 0, 15) as u16
5617 }
5618
5619 pub fn get_project_id(&self) -> u32 {
5620 self.ecx
5621 }
5622
5623 pub fn get_stepping_id(&self) -> u32 {
5624 self.edx
5625 }
5626
5627 pub fn get_vendor_brand(&self) -> Option<SoCVendorBrand> {
5628 if self.eax >= 3 {
5630 let r1 = self.read.cpuid2(EAX_SOC_VENDOR_INFO, 1);
5631 let r2 = self.read.cpuid2(EAX_SOC_VENDOR_INFO, 2);
5632 let r3 = self.read.cpuid2(EAX_SOC_VENDOR_INFO, 3);
5633 Some(SoCVendorBrand { data: [r1, r2, r3] })
5634 } else {
5635 None
5636 }
5637 }
5638
5639 pub fn get_vendor_attributes(&self) -> Option<SoCVendorAttributesIter<R>> {
5640 if self.eax > 3 {
5641 Some(SoCVendorAttributesIter {
5642 read: self.read.clone(),
5643 count: self.eax,
5644 current: 3,
5645 })
5646 } else {
5647 None
5648 }
5649 }
5650}
5651
5652impl<R: CpuIdReader> fmt::Debug for SoCVendorInfo<R> {
5653 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
5654 f.debug_struct("SoCVendorInfo")
5655 .field("soc_vendor_id", &self.get_soc_vendor_id())
5656 .field("project_id", &self.get_project_id())
5657 .field("stepping_id", &self.get_stepping_id())
5658 .field("vendor_brand", &self.get_vendor_brand())
5659 .field("vendor_attributes", &self.get_vendor_attributes())
5660 .finish()
5661 }
5662}
5663
5664pub struct SoCVendorAttributesIter<R: CpuIdReader> {
5666 read: R,
5667 count: u32,
5668 current: u32,
5669}
5670
5671impl<R: CpuIdReader> fmt::Debug for SoCVendorAttributesIter<R> {
5672 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
5673 f.debug_struct("SocVendorAttributesIter")
5674 .field("count", &self.count)
5675 .field("current", &self.current)
5676 .finish()
5677 }
5678}
5679
5680impl<R: CpuIdReader> Iterator for SoCVendorAttributesIter<R> {
5681 type Item = CpuIdResult;
5682
5683 fn next(&mut self) -> Option<CpuIdResult> {
5685 if self.current > self.count {
5686 return None;
5687 }
5688 self.count += 1;
5689 Some(self.read.cpuid2(EAX_SOC_VENDOR_INFO, self.count))
5690 }
5691}
5692
5693#[derive(Debug, PartialEq, Eq)]
5695#[repr(C)]
5696pub struct SoCVendorBrand {
5697 data: [CpuIdResult; 3],
5698}
5699
5700impl SoCVendorBrand {
5701 pub fn as_str(&self) -> &str {
5703 let brand_string_start = self as *const SoCVendorBrand as *const u8;
5704 let slice = unsafe {
5705 slice::from_raw_parts(brand_string_start, size_of::<SoCVendorBrand>())
5707 };
5708 str::from_utf8(slice).unwrap_or("InvalidSoCVendorString")
5709 }
5710
5711 #[deprecated(
5712 since = "10.0.0",
5713 note = "Use idiomatic function name `as_str` instead"
5714 )]
5715 pub fn as_string(&self) -> &str {
5716 self.as_str()
5717 }
5718}
5719
5720impl fmt::Display for SoCVendorBrand {
5721 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
5722 write!(f, "{}", self.as_str())
5723 }
5724}
5725
5726pub struct HypervisorInfo<R: CpuIdReader> {
5731 read: R,
5732 res: CpuIdResult,
5733}
5734
5735impl<R: CpuIdReader> fmt::Debug for HypervisorInfo<R> {
5736 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
5737 f.debug_struct("HypervisorInfo")
5738 .field("identify", &self.identify())
5739 .field("tsc_frequency", &self.tsc_frequency())
5740 .field("apic_frequency", &self.apic_frequency())
5741 .finish()
5742 }
5743}
5744
5745#[derive(Debug, Eq, PartialEq)]
5747pub enum Hypervisor {
5748 Xen,
5749 VMware,
5750 HyperV,
5751 KVM,
5752 QEMU,
5755 Bhyve,
5756 QNX,
5757 ACRN,
5758 Unknown(u32, u32, u32),
5759}
5760
5761impl<R: CpuIdReader> HypervisorInfo<R> {
5762 pub fn identify(&self) -> Hypervisor {
5773 match (self.res.ebx, self.res.ecx, self.res.edx) {
5774 (0x61774d56, 0x4d566572, 0x65726177) => Hypervisor::VMware,
5776 (0x566e6558, 0x65584d4d, 0x4d4d566e) => Hypervisor::Xen,
5778 (0x7263694d, 0x666f736f, 0x76482074) => Hypervisor::HyperV,
5780 (0x4b4d564b, 0x564b4d56, 0x0000004d) => Hypervisor::KVM,
5782 (0x54474354, 0x43544743, 0x47435447) => Hypervisor::QEMU,
5785 (0x76796862, 0x68622065, 0x20657679) => Hypervisor::Bhyve,
5788 (0x56794842, 0x48422045, 0x20455679) => Hypervisor::Bhyve,
5792 (0x51584e51, 0x53424d56, 0x00004751) => Hypervisor::QNX,
5796 (0x4e524341, 0x4e524341, 0x4e524341) => Hypervisor::ACRN,
5798 (ebx, ecx, edx) => Hypervisor::Unknown(ebx, ecx, edx),
5799 }
5800 }
5801
5802 pub fn tsc_frequency(&self) -> Option<u32> {
5804 if self.res.eax >= 0x40000010 {
5807 let virt_tinfo = self.read.cpuid2(0x40000010, 0);
5808 Some(virt_tinfo.eax)
5809 } else {
5810 None
5811 }
5812 }
5813
5814 pub fn apic_frequency(&self) -> Option<u32> {
5816 if self.res.eax >= 0x40000010 {
5818 let virt_tinfo = self.read.cpuid2(0x40000010, 0);
5819 Some(virt_tinfo.ebx)
5820 } else {
5821 None
5822 }
5823 }
5824}
5825
5826#[cfg(doctest)]
5827mod test_readme {
5828 macro_rules! external_doc_test {
5829 ($x:expr) => {
5830 #[doc = $x]
5831 extern "C" {}
5832 };
5833 }
5834
5835 external_doc_test!(include_str!("../README.md"));
5836}