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_avx_ifma(&self) -> bool {
3818 self.eax1.contains(ExtendedFeaturesEax1::AVX_IFMA)
3819 }
3820
3821 #[inline]
3826 pub const fn has_lam(&self) -> bool {
3827 self.eax1.contains(ExtendedFeaturesEax1::LAM)
3828 }
3829
3830 #[inline]
3835 pub const fn has_msrlist(&self) -> bool {
3836 self.eax1.contains(ExtendedFeaturesEax1::MSRLIST)
3837 }
3838
3839 #[inline]
3844 pub const fn has_invd_disable_post_bios_done(&self) -> bool {
3845 self.eax1
3846 .contains(ExtendedFeaturesEax1::INVD_DISABLE_POST_BIOS_DONE)
3847 }
3848
3849 #[inline]
3854 pub const fn has_avx_vnni_int8(&self) -> bool {
3855 self.edx1.contains(ExtendedFeaturesEdx1::AVX_VNNI_INT8)
3856 }
3857
3858 #[inline]
3863 pub const fn has_avx_ne_convert(&self) -> bool {
3864 self.edx1.contains(ExtendedFeaturesEdx1::AVX_NE_CONVERT)
3865 }
3866
3867 #[inline]
3872 pub const fn has_avx_vnni_int16(&self) -> bool {
3873 self.edx1.contains(ExtendedFeaturesEdx1::AVX_VNNI_INT16)
3874 }
3875
3876 #[inline]
3881 pub const fn has_prefetchi(&self) -> bool {
3882 self.edx1.contains(ExtendedFeaturesEdx1::PREFETCHI)
3883 }
3884
3885 #[inline]
3890 pub const fn has_uiret_uif(&self) -> bool {
3891 self.edx1.contains(ExtendedFeaturesEdx1::UIRET_UIF)
3892 }
3893
3894 #[inline]
3899 pub const fn has_cet_sss(&self) -> bool {
3900 self.edx1.contains(ExtendedFeaturesEdx1::CET_SSS)
3901 }
3902
3903 #[inline]
3908 pub const fn has_avx10(&self) -> bool {
3909 self.edx1.contains(ExtendedFeaturesEdx1::AVX10)
3910 }
3911}
3912
3913impl Debug for ExtendedFeatures {
3914 fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
3915 f.debug_struct("ExtendedFeatures")
3916 .field("ebx", &self.ebx)
3917 .field("ecx", &self.ecx)
3918 .field("mawau_value", &self.mawau_value())
3919 .finish()
3920 }
3921}
3922
3923bitflags! {
3924 #[repr(transparent)]
3925 #[derive(Debug, Clone, Copy, PartialEq, Eq)]
3926 struct ExtendedFeaturesEbx: u32 {
3927 const FSGSBASE = 1 << 0;
3929 const ADJUST_MSR = 1 << 1;
3931 const SGX = 1 << 2;
3933 const BMI1 = 1 << 3;
3935 const HLE = 1 << 4;
3937 const AVX2 = 1 << 5;
3939 const FDP = 1 << 6;
3941 const SMEP = 1 << 7;
3943 const BMI2 = 1 << 8;
3945 const REP_MOVSB_STOSB = 1 << 9;
3947 const INVPCID = 1 << 10;
3949 const RTM = 1 << 11;
3951 const RDTM = 1 << 12;
3953 const DEPRECATE_FPU_CS_DS = 1 << 13;
3955 const MPX = 1 << 14;
3957 const RDTA = 1 << 15;
3959 const AVX512F = 1 << 16;
3961 const AVX512DQ = 1 << 17;
3963 const RDSEED = 1 << 18;
3965 const ADX = 1 << 19;
3967 const SMAP = 1 << 20;
3969 const AVX512_IFMA = 1 << 21;
3971 const CLFLUSHOPT = 1 << 23;
3974 const CLWB = 1 << 24;
3976 const PROCESSOR_TRACE = 1 << 25;
3978 const AVX512PF = 1 << 26;
3980 const AVX512ER = 1 << 27;
3982 const AVX512CD = 1 << 28;
3984 const SHA = 1 << 29;
3986 const AVX512BW = 1 << 30;
3988 const AVX512VL = 1 << 31;
3990 }
3991}
3992
3993bitflags! {
3994 #[repr(transparent)]
3995 #[derive(Debug, Clone, Copy, PartialEq, Eq)]
3996 struct ExtendedFeaturesEcx: u32 {
3997 const PREFETCHWT1 = 1 << 0;
3999 const AVX512VBMI = 1 << 1;
4001 const UMIP = 1 << 2;
4003 const PKU = 1 << 3;
4005 const OSPKE = 1 << 4;
4007 const WAITPKG = 1 << 5;
4009 const AVX512VBMI2 = 1 << 6;
4011 const CETSS = 1 << 7;
4015 const GFNI = 1 << 8;
4017 const VAES = 1 << 9;
4019 const VPCLMULQDQ = 1 << 10;
4021 const AVX512VNNI = 1 << 11;
4023 const AVX512BITALG = 1 << 12;
4025 const TMEEN = 1 << 13;
4028 const AVX512VPOPCNTDQ = 1 << 14;
4030
4031 const LA57 = 1 << 16;
4035
4036 const RDPID = 1 << 22;
4040
4041 const SGX_LC = 1 << 30;
4045 }
4046}
4047
4048bitflags! {
4049 #[repr(transparent)]
4050 #[derive(Debug, Clone, Copy, PartialEq, Eq)]
4051 struct ExtendedFeaturesEdx: u32 {
4052 const AVX512_4VNNIW = 1 << 2;
4054 const AVX512_4FMAPS = 1 << 3;
4056 const AVX512_VP2INTERSECT = 1 << 8;
4058 const AMX_BF16 = 1 << 22;
4060 const AVX512_FP16 = 1 << 23;
4062 const AMX_TILE = 1 << 24;
4064 const AMX_INT8 = 1 << 25;
4066 }
4067}
4068
4069bitflags! {
4070 #[repr(transparent)]
4071 #[derive(Debug, Clone, Copy, PartialEq, Eq)]
4072 struct ExtendedFeaturesEax1: u32 {
4073 const AVX_VNNI = 1 << 4;
4076 const AVX512_BF16 = 1 << 5;
4078 const FZRM = 1 << 10;
4080 const FSRS = 1 << 11;
4082 const FSRCRS = 1 << 12;
4084 const HRESET = 1 << 22;
4086 const AVX_IFMA = 1 << 23;
4088 const LAM = 1 << 26;
4090 const MSRLIST = 1 << 27;
4092 const INVD_DISABLE_POST_BIOS_DONE = 1 << 30;
4094 }
4095}
4096
4097bitflags! {
4098 #[repr(transparent)]
4099 #[derive(Debug, Clone, Copy, PartialEq, Eq)]
4100 struct ExtendedFeaturesEdx1: u32 {
4101 const AVX_VNNI_INT8 = 1 << 4;
4104 const AVX_NE_CONVERT = 1 << 5;
4106 const AVX_VNNI_INT16 = 1 << 10;
4108 const PREFETCHI = 1 << 14;
4110 const UIRET_UIF = 1 << 17;
4112 const CET_SSS = 1 << 18;
4114 const AVX10 = 1 << 19;
4117 }
4118}
4119
4120pub struct DirectCacheAccessInfo {
4125 eax: u32,
4126}
4127
4128impl DirectCacheAccessInfo {
4129 pub fn get_dca_cap_value(&self) -> u32 {
4131 self.eax
4132 }
4133}
4134
4135impl Debug for DirectCacheAccessInfo {
4136 fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
4137 f.debug_struct("DirectCacheAccessInfo")
4138 .field("dca_cap_value", &self.get_dca_cap_value())
4139 .finish()
4140 }
4141}
4142
4143pub struct PerformanceMonitoringInfo {
4148 eax: u32,
4149 ebx: PerformanceMonitoringFeaturesEbx,
4150 _ecx: u32,
4151 edx: u32,
4152}
4153
4154impl PerformanceMonitoringInfo {
4155 pub fn version_id(&self) -> u8 {
4157 get_bits(self.eax, 0, 7) as u8
4158 }
4159
4160 pub fn number_of_counters(&self) -> u8 {
4162 get_bits(self.eax, 8, 15) as u8
4163 }
4164
4165 pub fn counter_bit_width(&self) -> u8 {
4167 get_bits(self.eax, 16, 23) as u8
4168 }
4169
4170 pub fn ebx_length(&self) -> u8 {
4172 get_bits(self.eax, 24, 31) as u8
4173 }
4174
4175 pub fn fixed_function_counters(&self) -> u8 {
4177 get_bits(self.edx, 0, 4) as u8
4178 }
4179
4180 pub fn fixed_function_counters_bit_width(&self) -> u8 {
4182 get_bits(self.edx, 5, 12) as u8
4183 }
4184
4185 check_bit_fn!(
4186 doc = "AnyThread deprecation",
4187 has_any_thread_deprecation,
4188 edx,
4189 15
4190 );
4191
4192 check_flag!(
4193 doc = "Core cycle event not available if 1.",
4194 is_core_cyc_ev_unavailable,
4195 ebx,
4196 PerformanceMonitoringFeaturesEbx::CORE_CYC_EV_UNAVAILABLE
4197 );
4198
4199 check_flag!(
4200 doc = "Instruction retired event not available if 1.",
4201 is_inst_ret_ev_unavailable,
4202 ebx,
4203 PerformanceMonitoringFeaturesEbx::INST_RET_EV_UNAVAILABLE
4204 );
4205
4206 check_flag!(
4207 doc = "Reference cycles event not available if 1.",
4208 is_ref_cycle_ev_unavailable,
4209 ebx,
4210 PerformanceMonitoringFeaturesEbx::REF_CYC_EV_UNAVAILABLE
4211 );
4212
4213 check_flag!(
4214 doc = "Last-level cache reference event not available if 1.",
4215 is_cache_ref_ev_unavailable,
4216 ebx,
4217 PerformanceMonitoringFeaturesEbx::CACHE_REF_EV_UNAVAILABLE
4218 );
4219
4220 check_flag!(
4221 doc = "Last-level cache misses event not available if 1.",
4222 is_ll_cache_miss_ev_unavailable,
4223 ebx,
4224 PerformanceMonitoringFeaturesEbx::LL_CACHE_MISS_EV_UNAVAILABLE
4225 );
4226
4227 check_flag!(
4228 doc = "Branch instruction retired event not available if 1.",
4229 is_branch_inst_ret_ev_unavailable,
4230 ebx,
4231 PerformanceMonitoringFeaturesEbx::BRANCH_INST_RET_EV_UNAVAILABLE
4232 );
4233
4234 check_flag!(
4235 doc = "Branch mispredict retired event not available if 1.",
4236 is_branch_midpred_ev_unavailable,
4237 ebx,
4238 PerformanceMonitoringFeaturesEbx::BRANCH_MISPRED_EV_UNAVAILABLE
4239 );
4240}
4241
4242impl Debug for PerformanceMonitoringInfo {
4243 fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
4244 f.debug_struct("PerformanceMonitoringInfo")
4245 .field("version_id", &self.version_id())
4246 .field("number_of_counters", &self.number_of_counters())
4247 .field("counter_bit_width", &self.counter_bit_width())
4248 .field("ebx_length", &self.ebx_length())
4249 .field("fixed_function_counters", &self.fixed_function_counters())
4250 .field(
4251 "fixed_function_counters_bit_width",
4252 &self.fixed_function_counters_bit_width(),
4253 )
4254 .finish()
4255 }
4256}
4257
4258bitflags! {
4259 #[repr(transparent)]
4260 #[derive(Debug, Clone, Copy, PartialEq, Eq)]
4261 struct PerformanceMonitoringFeaturesEbx: u32 {
4262 const CORE_CYC_EV_UNAVAILABLE = 1 << 0;
4264 const INST_RET_EV_UNAVAILABLE = 1 << 1;
4266 const REF_CYC_EV_UNAVAILABLE = 1 << 2;
4268 const CACHE_REF_EV_UNAVAILABLE = 1 << 3;
4270 const LL_CACHE_MISS_EV_UNAVAILABLE = 1 << 4;
4272 const BRANCH_INST_RET_EV_UNAVAILABLE = 1 << 5;
4274 const BRANCH_MISPRED_EV_UNAVAILABLE = 1 << 6;
4276 }
4277}
4278
4279#[derive(Clone)]
4288pub struct ExtendedTopologyIter<R: CpuIdReader> {
4289 read: R,
4290 level: u32,
4291 is_v2: bool,
4292}
4293
4294#[derive(PartialEq, Eq)]
4298pub struct ExtendedTopologyLevel {
4299 eax: u32,
4300 ebx: u32,
4301 ecx: u32,
4302 edx: u32,
4303}
4304
4305impl fmt::Debug for ExtendedTopologyLevel {
4306 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
4307 f.debug_struct("ExtendedTopologyLevel")
4308 .field("processors", &self.processors())
4309 .field("number", &self.level_number())
4310 .field("type", &self.level_type())
4311 .field("x2apic_id", &self.x2apic_id())
4312 .field("next_apic_id", &self.shift_right_for_next_apic_id())
4313 .finish()
4314 }
4315}
4316
4317impl ExtendedTopologyLevel {
4318 pub fn processors(&self) -> u16 {
4321 get_bits(self.ebx, 0, 15) as u16
4322 }
4323
4324 pub fn level_number(&self) -> u8 {
4326 get_bits(self.ecx, 0, 7) as u8
4327 }
4328
4329 pub fn level_type(&self) -> TopologyType {
4331 match get_bits(self.ecx, 8, 15) {
4332 0 => TopologyType::Invalid,
4333 1 => TopologyType::SMT,
4334 2 => TopologyType::Core,
4335 3 => TopologyType::Module,
4336 4 => TopologyType::Tile,
4337 5 => TopologyType::Die,
4338 _ => unreachable!(),
4339 }
4340 }
4341
4342 pub fn x2apic_id(&self) -> u32 {
4344 self.edx
4345 }
4346
4347 pub fn shift_right_for_next_apic_id(&self) -> u32 {
4350 get_bits(self.eax, 0, 4)
4351 }
4352}
4353
4354#[derive(PartialEq, Eq, Debug)]
4356pub enum TopologyType {
4357 Invalid = 0,
4358 SMT = 1,
4360 Core = 2,
4361 Module = 3,
4362 Tile = 4,
4363 Die = 5,
4364}
4365
4366impl fmt::Display for TopologyType {
4367 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
4368 let data = match self {
4369 TopologyType::Invalid => "Invalid",
4370 TopologyType::SMT => "SMT",
4371 TopologyType::Core => "Core",
4372 TopologyType::Module => "Module",
4373 TopologyType::Tile => "Tile",
4374 TopologyType::Die => "Die",
4375 };
4376
4377 f.write_str(data)
4378 }
4379}
4380
4381impl<R: CpuIdReader> Iterator for ExtendedTopologyIter<R> {
4382 type Item = ExtendedTopologyLevel;
4383
4384 fn next(&mut self) -> Option<ExtendedTopologyLevel> {
4385 let res = if self.is_v2 {
4386 self.read.cpuid2(EAX_EXTENDED_TOPOLOGY_INFO_V2, self.level)
4387 } else {
4388 self.read.cpuid2(EAX_EXTENDED_TOPOLOGY_INFO, self.level)
4389 };
4390 self.level += 1;
4391
4392 let et = ExtendedTopologyLevel {
4393 eax: res.eax,
4394 ebx: res.ebx,
4395 ecx: res.ecx,
4396 edx: res.edx,
4397 };
4398
4399 match et.level_type() {
4400 TopologyType::Invalid => None,
4401 _ => Some(et),
4402 }
4403 }
4404}
4405
4406impl<R: CpuIdReader> Debug for ExtendedTopologyIter<R> {
4407 fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
4408 let mut debug = f.debug_list();
4409 self.clone().for_each(|ref item| {
4410 debug.entry(item);
4411 });
4412 debug.finish()
4413 }
4414}
4415
4416bitflags! {
4417 #[repr(transparent)]
4418 #[derive(Debug, Clone, Copy, PartialEq, Eq)]
4419 struct ExtendedStateInfoXCR0Flags: u32 {
4420 const LEGACY_X87 = 1 << 0;
4422
4423 const SSE128 = 1 << 1;
4425
4426 const AVX256 = 1 << 2;
4428
4429 const MPX_BNDREGS = 1 << 3;
4431
4432 const MPX_BNDCSR = 1 << 4;
4434
4435 const AVX512_OPMASK = 1 << 5;
4437
4438 const AVX512_ZMM_HI256 = 1 << 6;
4440
4441 const AVX512_ZMM_HI16 = 1 << 7;
4443
4444 const PKRU = 1 << 9;
4446
4447 const IA32_XSS_HDC = 1 << 13;
4449
4450 const AMX_TILECFG = 1 << 17;
4452
4453 const AMX_TILEDATA = 1 << 18;
4455 }
4456}
4457
4458bitflags! {
4459 #[repr(transparent)]
4460 #[derive(Debug, Clone, Copy, PartialEq, Eq)]
4461 struct ExtendedStateInfoXSSFlags: u32 {
4462 const PT = 1 << 8;
4464
4465 const PASID = 1 << 10;
4467
4468 const CET_USER = 1 << 11;
4470
4471 const CET_SUPERVISOR = 1 << 12;
4473
4474 const HDC = 1 << 13;
4476
4477 const UINTR = 1 << 14;
4479
4480 const LBR = 1 << 15;
4482
4483 const HWP = 1 << 16;
4485 }
4486}
4487
4488pub struct ExtendedStateInfo<R: CpuIdReader> {
4493 read: R,
4494 eax: ExtendedStateInfoXCR0Flags,
4495 ebx: u32,
4496 ecx: u32,
4497 _edx: u32,
4498 eax1: u32,
4499 ebx1: u32,
4500 ecx1: ExtendedStateInfoXSSFlags,
4501 _edx1: u32,
4502}
4503
4504impl<F: CpuIdReader> ExtendedStateInfo<F> {
4505 check_flag!(
4506 doc = "Support for legacy x87 in XCR0.",
4507 xcr0_supports_legacy_x87,
4508 eax,
4509 ExtendedStateInfoXCR0Flags::LEGACY_X87
4510 );
4511
4512 check_flag!(
4513 doc = "Support for SSE 128-bit in XCR0.",
4514 xcr0_supports_sse_128,
4515 eax,
4516 ExtendedStateInfoXCR0Flags::SSE128
4517 );
4518
4519 check_flag!(
4520 doc = "Support for AVX 256-bit in XCR0.",
4521 xcr0_supports_avx_256,
4522 eax,
4523 ExtendedStateInfoXCR0Flags::AVX256
4524 );
4525
4526 check_flag!(
4527 doc = "Support for MPX BNDREGS in XCR0.",
4528 xcr0_supports_mpx_bndregs,
4529 eax,
4530 ExtendedStateInfoXCR0Flags::MPX_BNDREGS
4531 );
4532
4533 check_flag!(
4534 doc = "Support for MPX BNDCSR in XCR0.",
4535 xcr0_supports_mpx_bndcsr,
4536 eax,
4537 ExtendedStateInfoXCR0Flags::MPX_BNDCSR
4538 );
4539
4540 check_flag!(
4541 doc = "Support for AVX512 OPMASK in XCR0.",
4542 xcr0_supports_avx512_opmask,
4543 eax,
4544 ExtendedStateInfoXCR0Flags::AVX512_OPMASK
4545 );
4546
4547 check_flag!(
4548 doc = "Support for AVX512 ZMM Hi256 XCR0.",
4549 xcr0_supports_avx512_zmm_hi256,
4550 eax,
4551 ExtendedStateInfoXCR0Flags::AVX512_ZMM_HI256
4552 );
4553
4554 check_flag!(
4555 doc = "Support for AVX512 ZMM Hi16 in XCR0.",
4556 xcr0_supports_avx512_zmm_hi16,
4557 eax,
4558 ExtendedStateInfoXCR0Flags::AVX512_ZMM_HI16
4559 );
4560
4561 check_flag!(
4562 doc = "Support for PKRU in XCR0.",
4563 xcr0_supports_pkru,
4564 eax,
4565 ExtendedStateInfoXCR0Flags::PKRU
4566 );
4567
4568 check_flag!(
4569 doc = "Support for PT in IA32_XSS.",
4570 ia32_xss_supports_pt,
4571 ecx1,
4572 ExtendedStateInfoXSSFlags::PT
4573 );
4574
4575 check_flag!(
4576 doc = "Support for HDC in IA32_XSS.",
4577 ia32_xss_supports_hdc,
4578 ecx1,
4579 ExtendedStateInfoXSSFlags::HDC
4580 );
4581
4582 pub fn xsave_area_size_enabled_features(&self) -> u32 {
4586 self.ebx
4587 }
4588
4589 pub fn xsave_area_size_supported_features(&self) -> u32 {
4593 self.ecx
4594 }
4595
4596 pub fn has_xsaveopt(&self) -> bool {
4598 self.eax1 & 0x1 > 0
4599 }
4600
4601 pub fn has_xsavec(&self) -> bool {
4603 self.eax1 & 0b10 > 0
4604 }
4605
4606 pub fn has_xgetbv(&self) -> bool {
4608 self.eax1 & 0b100 > 0
4609 }
4610
4611 pub fn has_xsaves_xrstors(&self) -> bool {
4613 self.eax1 & 0b1000 > 0
4614 }
4615
4616 pub fn xsave_size(&self) -> u32 {
4618 self.ebx1
4619 }
4620
4621 pub fn iter(&self) -> ExtendedStateIter<F> {
4623 ExtendedStateIter {
4624 read: self.read.clone(),
4625 level: 1,
4626 supported_xcr0: self.eax.bits(),
4627 supported_xss: self.ecx1.bits(),
4628 }
4629 }
4630}
4631
4632impl<R: CpuIdReader> Debug for ExtendedStateInfo<R> {
4633 fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
4634 f.debug_struct("ExtendedStateInfo")
4635 .field("eax", &self.eax)
4636 .field("ecx1", &self.ecx1)
4637 .field(
4638 "xsave_area_size_enabled_features",
4639 &self.xsave_area_size_enabled_features(),
4640 )
4641 .field(
4642 "xsave_area_size_supported_features",
4643 &self.xsave_area_size_supported_features(),
4644 )
4645 .field("has_xsaveopt", &self.has_xsaveopt())
4646 .field("has_xsavec", &self.has_xsavec())
4647 .field("has_xgetbv", &self.has_xgetbv())
4648 .field("has_xsaves_xrstors", &self.has_xsaves_xrstors())
4649 .field("xsave_size", &self.xsave_size())
4650 .field("extended_state_iter", &self.iter())
4651 .finish()
4652 }
4653}
4654
4655#[derive(Clone)]
4657pub struct ExtendedStateIter<R: CpuIdReader> {
4658 read: R,
4659 level: u32,
4660 supported_xcr0: u32,
4661 supported_xss: u32,
4662}
4663
4664impl<R: CpuIdReader> Iterator for ExtendedStateIter<R> {
4671 type Item = ExtendedState;
4672
4673 fn next(&mut self) -> Option<ExtendedState> {
4674 self.level += 1;
4675 if self.level > 31 {
4676 return None;
4677 }
4678
4679 let bit = 1 << self.level;
4680 if (self.supported_xcr0 & bit > 0) || (self.supported_xss & bit > 0) {
4681 let res = self.read.cpuid2(EAX_EXTENDED_STATE_INFO, self.level);
4682 return Some(ExtendedState {
4683 subleaf: self.level,
4684 eax: res.eax,
4685 ebx: res.ebx,
4686 ecx: res.ecx,
4687 });
4688 }
4689
4690 self.next()
4691 }
4692}
4693
4694impl<R: CpuIdReader> Debug for ExtendedStateIter<R> {
4695 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
4696 let mut debug = f.debug_list();
4697 self.clone().for_each(|ref item| {
4698 debug.entry(item);
4699 });
4700 debug.finish()
4701 }
4702}
4703
4704#[derive(PartialEq, Eq, Debug)]
4706#[repr(u32)]
4707pub enum ExtendedRegisterType {
4708 Avx,
4709 MpxBndregs,
4710 MpxBndcsr,
4711 Avx512Opmask,
4712 Avx512ZmmHi256,
4713 Avx512ZmmHi16,
4714 Pt,
4715 Pkru,
4716 Hdc,
4717 Unknown(u32),
4718}
4719
4720impl From<u32> for ExtendedRegisterType {
4721 fn from(value: u32) -> ExtendedRegisterType {
4722 match value {
4723 0x2 => ExtendedRegisterType::Avx,
4724 0x3 => ExtendedRegisterType::MpxBndregs,
4725 0x4 => ExtendedRegisterType::MpxBndcsr,
4726 0x5 => ExtendedRegisterType::Avx512Opmask,
4727 0x6 => ExtendedRegisterType::Avx512ZmmHi256,
4728 0x7 => ExtendedRegisterType::Avx512ZmmHi16,
4729 0x8 => ExtendedRegisterType::Pt,
4730 0x9 => ExtendedRegisterType::Pkru,
4731 0xd => ExtendedRegisterType::Hdc,
4732 x => ExtendedRegisterType::Unknown(x),
4733 }
4734 }
4735}
4736
4737impl fmt::Display for ExtendedRegisterType {
4738 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
4739 let data = match self {
4740 ExtendedRegisterType::Avx => "AVX/YMM",
4741 ExtendedRegisterType::MpxBndregs => "MPX BNDREGS",
4742 ExtendedRegisterType::MpxBndcsr => "MPX BNDCSR",
4743 ExtendedRegisterType::Avx512Opmask => "AVX-512 opmask",
4744 ExtendedRegisterType::Avx512ZmmHi256 => "AVX-512 ZMM_Hi256",
4745 ExtendedRegisterType::Avx512ZmmHi16 => "AVX-512 Hi16_ZMM",
4746 ExtendedRegisterType::Pkru => "PKRU",
4747 ExtendedRegisterType::Pt => "PT",
4748 ExtendedRegisterType::Hdc => "HDC",
4749 ExtendedRegisterType::Unknown(t) => {
4750 return write!(f, "Unknown({})", t);
4751 }
4752 };
4753
4754 f.write_str(data)
4755 }
4756}
4757
4758#[derive(PartialEq, Eq, Debug)]
4760pub enum ExtendedRegisterStateLocation {
4761 Xcr0,
4762 Ia32Xss,
4763}
4764
4765impl fmt::Display for ExtendedRegisterStateLocation {
4766 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
4767 let data = match self {
4768 ExtendedRegisterStateLocation::Xcr0 => "XCR0 (user state)",
4769 ExtendedRegisterStateLocation::Ia32Xss => "IA32_XSS (supervisor state)",
4770 };
4771
4772 f.write_str(data)
4773 }
4774}
4775
4776pub struct ExtendedState {
4778 pub subleaf: u32,
4779 eax: u32,
4780 ebx: u32,
4781 ecx: u32,
4782}
4783
4784impl ExtendedState {
4785 pub fn register(&self) -> ExtendedRegisterType {
4787 self.subleaf.into()
4788 }
4789
4790 pub fn size(&self) -> u32 {
4794 self.eax
4795 }
4796
4797 pub fn offset(&self) -> u32 {
4800 self.ebx
4801 }
4802
4803 pub fn location(&self) -> ExtendedRegisterStateLocation {
4804 if self.is_in_xcr0() {
4805 ExtendedRegisterStateLocation::Xcr0
4806 } else {
4807 ExtendedRegisterStateLocation::Ia32Xss
4808 }
4809 }
4810
4811 pub fn is_in_ia32_xss(&self) -> bool {
4817 self.ecx & 0b1 > 0
4818 }
4819
4820 pub fn is_in_xcr0(&self) -> bool {
4825 self.ecx & 0b1 == 0
4826 }
4827
4828 pub fn is_compacted_format(&self) -> bool {
4833 self.ecx & 0b10 > 0
4834 }
4835}
4836
4837impl Debug for ExtendedState {
4838 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
4839 f.debug_struct("ExtendedState")
4840 .field("size", &self.size())
4841 .field("offset", &self.offset())
4842 .field("is_in_ia32_xss", &self.is_in_ia32_xss())
4843 .field("is_in_xcr0", &self.is_in_xcr0())
4844 .field("is_compacted_format", &self.is_compacted_format())
4845 .finish()
4846 }
4847}
4848
4849pub struct RdtMonitoringInfo<R: CpuIdReader> {
4855 read: R,
4856 ebx: u32,
4857 edx: u32,
4858}
4859
4860impl<R: CpuIdReader> RdtMonitoringInfo<R> {
4861 pub fn rmid_range(&self) -> u32 {
4863 self.ebx
4864 }
4865
4866 check_bit_fn!(
4867 doc = "Supports L3 Cache Intel RDT Monitoring.",
4868 has_l3_monitoring,
4869 edx,
4870 1
4871 );
4872
4873 pub fn l3_monitoring(&self) -> Option<L3MonitoringInfo> {
4875 if self.has_l3_monitoring() {
4876 let res = self.read.cpuid2(EAX_RDT_MONITORING, 1);
4877 Some(L3MonitoringInfo {
4878 ebx: res.ebx,
4879 ecx: res.ecx,
4880 edx: res.edx,
4881 })
4882 } else {
4883 None
4884 }
4885 }
4886}
4887
4888impl<R: CpuIdReader> Debug for RdtMonitoringInfo<R> {
4889 fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
4890 f.debug_struct("RdtMonitoringInfo")
4891 .field("rmid_range", &self.rmid_range())
4892 .field("l3_monitoring", &self.l3_monitoring())
4893 .finish()
4894 }
4895}
4896
4897pub struct L3MonitoringInfo {
4899 ebx: u32,
4900 ecx: u32,
4901 edx: u32,
4902}
4903
4904impl L3MonitoringInfo {
4905 pub fn conversion_factor(&self) -> u32 {
4907 self.ebx
4908 }
4909
4910 pub fn maximum_rmid_range(&self) -> u32 {
4912 self.ecx
4913 }
4914
4915 check_bit_fn!(
4916 doc = "Supports occupancy monitoring.",
4917 has_occupancy_monitoring,
4918 edx,
4919 0
4920 );
4921
4922 check_bit_fn!(
4923 doc = "Supports total bandwidth monitoring.",
4924 has_total_bandwidth_monitoring,
4925 edx,
4926 1
4927 );
4928
4929 check_bit_fn!(
4930 doc = "Supports local bandwidth monitoring.",
4931 has_local_bandwidth_monitoring,
4932 edx,
4933 2
4934 );
4935}
4936
4937impl Debug for L3MonitoringInfo {
4938 fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
4939 f.debug_struct("L3MonitoringInfo")
4940 .field("conversion_factor", &self.conversion_factor())
4941 .field("maximum_rmid_range", &self.maximum_rmid_range())
4942 .finish()
4943 }
4944}
4945
4946pub struct RdtAllocationInfo<R: CpuIdReader> {
4951 read: R,
4952 ebx: u32,
4953}
4954
4955impl<R: CpuIdReader> RdtAllocationInfo<R> {
4956 check_bit_fn!(doc = "Supports L3 Cache Allocation.", has_l3_cat, ebx, 1);
4957
4958 check_bit_fn!(doc = "Supports L2 Cache Allocation.", has_l2_cat, ebx, 2);
4959
4960 check_bit_fn!(
4961 doc = "Supports Memory Bandwidth Allocation.",
4962 has_memory_bandwidth_allocation,
4963 ebx,
4964 3
4965 );
4966
4967 pub fn l3_cat(&self) -> Option<L3CatInfo> {
4969 if self.has_l3_cat() {
4970 let res = self.read.cpuid2(EAX_RDT_ALLOCATION, 1);
4971 Some(L3CatInfo {
4972 eax: res.eax,
4973 ebx: res.ebx,
4974 ecx: res.ecx,
4975 edx: res.edx,
4976 })
4977 } else {
4978 None
4979 }
4980 }
4981
4982 pub fn l2_cat(&self) -> Option<L2CatInfo> {
4984 if self.has_l2_cat() {
4985 let res = self.read.cpuid2(EAX_RDT_ALLOCATION, 2);
4986 Some(L2CatInfo {
4987 eax: res.eax,
4988 ebx: res.ebx,
4989 edx: res.edx,
4990 })
4991 } else {
4992 None
4993 }
4994 }
4995
4996 pub fn memory_bandwidth_allocation(&self) -> Option<MemBwAllocationInfo> {
4998 if self.has_memory_bandwidth_allocation() {
4999 let res = self.read.cpuid2(EAX_RDT_ALLOCATION, 3);
5000 Some(MemBwAllocationInfo {
5001 eax: res.eax,
5002 ecx: res.ecx,
5003 edx: res.edx,
5004 })
5005 } else {
5006 None
5007 }
5008 }
5009}
5010
5011impl<R: CpuIdReader> Debug for RdtAllocationInfo<R> {
5012 fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
5013 f.debug_struct("RdtAllocationInfo")
5014 .field("l3_cat", &self.l3_cat())
5015 .field("l2_cat", &self.l2_cat())
5016 .field(
5017 "memory_bandwidth_allocation",
5018 &self.memory_bandwidth_allocation(),
5019 )
5020 .finish()
5021 }
5022}
5023
5024pub struct L3CatInfo {
5026 eax: u32,
5027 ebx: u32,
5028 ecx: u32,
5029 edx: u32,
5030}
5031
5032impl L3CatInfo {
5033 pub fn capacity_mask_length(&self) -> u8 {
5035 (get_bits(self.eax, 0, 4) + 1) as u8
5036 }
5037
5038 pub fn isolation_bitmap(&self) -> u32 {
5040 self.ebx
5041 }
5042
5043 pub fn highest_cos(&self) -> u16 {
5045 get_bits(self.edx, 0, 15) as u16
5046 }
5047
5048 check_bit_fn!(
5049 doc = "Is Code and Data Prioritization Technology supported?",
5050 has_code_data_prioritization,
5051 ecx,
5052 2
5053 );
5054}
5055
5056impl Debug for L3CatInfo {
5057 fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
5058 f.debug_struct("L3CatInfo")
5059 .field("capacity_mask_length", &self.capacity_mask_length())
5060 .field("isolation_bitmap", &self.isolation_bitmap())
5061 .field("highest_cos", &self.highest_cos())
5062 .finish()
5063 }
5064}
5065
5066#[derive(Eq, PartialEq)]
5068pub struct L2CatInfo {
5069 eax: u32,
5070 ebx: u32,
5071 edx: u32,
5072}
5073
5074impl L2CatInfo {
5075 pub fn capacity_mask_length(&self) -> u8 {
5077 (get_bits(self.eax, 0, 4) + 1) as u8
5078 }
5079
5080 pub fn isolation_bitmap(&self) -> u32 {
5082 self.ebx
5083 }
5084
5085 pub fn highest_cos(&self) -> u16 {
5087 get_bits(self.edx, 0, 15) as u16
5088 }
5089}
5090
5091impl Debug for L2CatInfo {
5092 fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
5093 f.debug_struct("L2CatInfo")
5094 .field("capacity_mask_length", &self.capacity_mask_length())
5095 .field("isolation_bitmap", &self.isolation_bitmap())
5096 .field("highest_cos", &self.highest_cos())
5097 .finish()
5098 }
5099}
5100
5101#[derive(Eq, PartialEq)]
5103pub struct MemBwAllocationInfo {
5104 eax: u32,
5105 ecx: u32,
5106 edx: u32,
5107}
5108
5109impl MemBwAllocationInfo {
5110 pub fn max_hba_throttling(&self) -> u16 {
5112 (get_bits(self.eax, 0, 11) + 1) as u16
5113 }
5114
5115 pub fn highest_cos(&self) -> u16 {
5117 get_bits(self.edx, 0, 15) as u16
5118 }
5119
5120 check_bit_fn!(
5121 doc = "Reports whether the response of the delay values is linear.",
5122 has_linear_response_delay,
5123 ecx,
5124 2
5125 );
5126}
5127
5128impl Debug for MemBwAllocationInfo {
5129 fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
5130 f.debug_struct("MemBwAllocationInfo")
5131 .field("max_hba_throttling", &self.max_hba_throttling())
5132 .field("highest_cos", &self.highest_cos())
5133 .field(
5134 "has_linear_response_delay",
5135 &self.has_linear_response_delay(),
5136 )
5137 .finish()
5138 }
5139}
5140
5141pub struct SgxInfo<R: CpuIdReader> {
5148 read: R,
5149 eax: u32,
5150 ebx: u32,
5151 _ecx: u32,
5152 edx: u32,
5153 eax1: u32,
5154 ebx1: u32,
5155 ecx1: u32,
5156 edx1: u32,
5157}
5158
5159impl<F: CpuIdReader> SgxInfo<F> {
5160 check_bit_fn!(doc = "Has SGX1 support.", has_sgx1, eax, 0);
5161 check_bit_fn!(doc = "Has SGX2 support.", has_sgx2, eax, 1);
5162
5163 check_bit_fn!(
5164 doc = "Supports ENCLV instruction leaves EINCVIRTCHILD, EDECVIRTCHILD, and ESETCONTEXT.",
5165 has_enclv_leaves_einvirtchild_edecvirtchild_esetcontext,
5166 eax,
5167 5
5168 );
5169
5170 check_bit_fn!(
5171 doc = "Supports ENCLS instruction leaves ETRACKC, ERDINFO, ELDBC, and ELDUC.",
5172 has_encls_leaves_etrackc_erdinfo_eldbc_elduc,
5173 eax,
5174 6
5175 );
5176
5177 pub fn miscselect(&self) -> u32 {
5179 self.ebx
5180 }
5181
5182 pub fn max_enclave_size_non_64bit(&self) -> u8 {
5184 get_bits(self.edx, 0, 7) as u8
5185 }
5186
5187 pub fn max_enclave_size_64bit(&self) -> u8 {
5189 get_bits(self.edx, 8, 15) as u8
5190 }
5191
5192 pub fn secs_attributes(&self) -> (u64, u64) {
5194 let lower = self.eax1 as u64 | (self.ebx1 as u64) << 32;
5195 let upper = self.ecx1 as u64 | (self.edx1 as u64) << 32;
5196 (lower, upper)
5197 }
5198 pub fn iter(&self) -> SgxSectionIter<F> {
5200 SgxSectionIter {
5201 read: self.read.clone(),
5202 current: 2,
5203 }
5204 }
5205}
5206
5207impl<R: CpuIdReader> Debug for SgxInfo<R> {
5208 fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
5209 f.debug_struct("SgxInfo")
5210 .field("has_sgx1", &self.has_sgx1())
5211 .field("has_sgx2", &self.has_sgx2())
5212 .field("miscselect", &self.miscselect())
5213 .field(
5214 "max_enclave_size_non_64bit",
5215 &self.max_enclave_size_non_64bit(),
5216 )
5217 .field("max_enclave_size_64bit", &self.max_enclave_size_64bit())
5218 .field(
5219 "has_encls_leaves_etrackc_erdinfo_eldbc_elduc",
5220 &self.has_encls_leaves_etrackc_erdinfo_eldbc_elduc(),
5221 )
5222 .field(
5223 "has_enclv_leaves_einvirtchild_edecvirtchild_esetcontext",
5224 &self.has_enclv_leaves_einvirtchild_edecvirtchild_esetcontext(),
5225 )
5226 .field("sgx_section_iter", &self.iter())
5227 .finish()
5228 }
5229}
5230
5231#[derive(Clone)]
5233pub struct SgxSectionIter<R: CpuIdReader> {
5234 read: R,
5235 current: u32,
5236}
5237
5238impl<R: CpuIdReader> Iterator for SgxSectionIter<R> {
5239 type Item = SgxSectionInfo;
5240
5241 fn next(&mut self) -> Option<SgxSectionInfo> {
5242 let res = self.read.cpuid2(EAX_SGX, self.current);
5243 self.current += 1;
5244 match get_bits(res.eax, 0, 3) {
5245 0b0001 => Some(SgxSectionInfo::Epc(EpcSection {
5246 eax: res.eax,
5247 ebx: res.ebx,
5248 ecx: res.ecx,
5249 edx: res.edx,
5250 })),
5251 _ => None,
5252 }
5253 }
5254}
5255
5256impl<R: CpuIdReader> Debug for SgxSectionIter<R> {
5257 fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
5258 let mut debug = f.debug_list();
5259 self.clone().for_each(|ref item| {
5260 debug.entry(item);
5261 });
5262 debug.finish()
5263 }
5264}
5265
5266#[derive(Debug)]
5270pub enum SgxSectionInfo {
5271 Epc(EpcSection),
5273}
5274
5275#[derive(Debug)]
5277pub struct EpcSection {
5278 eax: u32,
5279 ebx: u32,
5280 ecx: u32,
5281 edx: u32,
5282}
5283
5284impl EpcSection {
5285 pub fn physical_base(&self) -> u64 {
5287 let lower = (get_bits(self.eax, 12, 31) << 12) as u64;
5288 let upper = (get_bits(self.ebx, 0, 19) as u64) << 32;
5289 lower | upper
5290 }
5291
5292 pub fn size(&self) -> u64 {
5294 let lower = (get_bits(self.ecx, 12, 31) << 12) as u64;
5295 let upper = (get_bits(self.edx, 0, 19) as u64) << 32;
5296 lower | upper
5297 }
5298}
5299
5300pub struct ProcessorTraceInfo {
5305 _eax: u32,
5306 ebx: u32,
5307 ecx: u32,
5308 _edx: u32,
5309 leaf1: Option<CpuIdResult>,
5310}
5311
5312impl ProcessorTraceInfo {
5313 check_bit_fn!(
5315 doc = "If true, Indicates that IA32_RTIT_CTL.CR3Filter can be set to 1, and \
5316 that IA32_RTIT_CR3_MATCH MSR can be accessed.",
5317 has_rtit_cr3_match,
5318 ebx,
5319 0
5320 );
5321 check_bit_fn!(
5322 doc = "If true, Indicates support of Configurable PSB and Cycle-Accurate Mode.",
5323 has_configurable_psb_and_cycle_accurate_mode,
5324 ebx,
5325 1
5326 );
5327 check_bit_fn!(
5328 doc = "If true, Indicates support of IP Filtering, TraceStop filtering, and \
5329 preservation of Intel PT MSRs across warm reset.",
5330 has_ip_tracestop_filtering,
5331 ebx,
5332 2
5333 );
5334 check_bit_fn!(
5335 doc = "If true, Indicates support of MTC timing packet and suppression of \
5336 COFI-based packets.",
5337 has_mtc_timing_packet_coefi_suppression,
5338 ebx,
5339 3
5340 );
5341
5342 check_bit_fn!(
5343 doc = "Indicates support of PTWRITE. Writes can set IA32_RTIT_CTL\\[12\\] (PTWEn \
5344 and IA32_RTIT_CTL\\[5\\] (FUPonPTW), and PTWRITE can generate packets",
5345 has_ptwrite,
5346 ebx,
5347 4
5348 );
5349
5350 check_bit_fn!(
5351 doc = "Support of Power Event Trace. Writes can set IA32_RTIT_CTL\\[4\\] (PwrEvtEn) \
5352 enabling Power Event Trace packet generation.",
5353 has_power_event_trace,
5354 ebx,
5355 5
5356 );
5357
5358 check_bit_fn!(
5360 doc = "If true, Tracing can be enabled with IA32_RTIT_CTL.ToPA = 1, hence \
5361 utilizing the ToPA output scheme; IA32_RTIT_OUTPUT_BASE and \
5362 IA32_RTIT_OUTPUT_MASK_PTRS MSRs can be accessed.",
5363 has_topa,
5364 ecx,
5365 0
5366 );
5367 check_bit_fn!(
5368 doc = "If true, ToPA tables can hold any number of output entries, up to the \
5369 maximum allowed by the MaskOrTableOffset field of \
5370 IA32_RTIT_OUTPUT_MASK_PTRS.",
5371 has_topa_maximum_entries,
5372 ecx,
5373 1
5374 );
5375 check_bit_fn!(
5376 doc = "If true, Indicates support of Single-Range Output scheme.",
5377 has_single_range_output_scheme,
5378 ecx,
5379 2
5380 );
5381 check_bit_fn!(
5382 doc = "If true, Indicates support of output to Trace Transport subsystem.",
5383 has_trace_transport_subsystem,
5384 ecx,
5385 3
5386 );
5387 check_bit_fn!(
5388 doc = "If true, Generated packets which contain IP payloads have LIP values, \
5389 which include the CS base component.",
5390 has_lip_with_cs_base,
5391 ecx,
5392 31
5393 );
5394
5395 pub fn configurable_address_ranges(&self) -> u8 {
5397 self.leaf1.map_or(0, |res| get_bits(res.eax, 0, 2) as u8)
5398 }
5399
5400 pub fn supported_mtc_period_encodings(&self) -> u16 {
5402 self.leaf1.map_or(0, |res| get_bits(res.eax, 16, 31) as u16)
5403 }
5404
5405 pub fn supported_cycle_threshold_value_encodings(&self) -> u16 {
5407 self.leaf1.map_or(0, |res| get_bits(res.ebx, 0, 15) as u16)
5408 }
5409
5410 pub fn supported_psb_frequency_encodings(&self) -> u16 {
5412 self.leaf1.map_or(0, |res| get_bits(res.ebx, 16, 31) as u16)
5413 }
5414}
5415
5416impl Debug for ProcessorTraceInfo {
5417 fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
5418 f.debug_struct("ProcessorTraceInfo")
5419 .field(
5420 "configurable_address_ranges",
5421 &self.configurable_address_ranges(),
5422 )
5423 .field(
5424 "supported_mtc_period_encodings",
5425 &self.supported_mtc_period_encodings(),
5426 )
5427 .field(
5428 "supported_cycle_threshold_value_encodings",
5429 &self.supported_cycle_threshold_value_encodings(),
5430 )
5431 .field(
5432 "supported_psb_frequency_encodings",
5433 &self.supported_psb_frequency_encodings(),
5434 )
5435 .finish()
5436 }
5437}
5438
5439pub struct TscInfo {
5444 eax: u32,
5445 ebx: u32,
5446 ecx: u32,
5447}
5448
5449impl fmt::Debug for TscInfo {
5450 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
5451 f.debug_struct("TscInfo")
5452 .field("denominator", &self.denominator())
5453 .field("numerator", &self.numerator())
5454 .field("nominal_frequency", &self.nominal_frequency())
5455 .field("tsc_frequency", &self.tsc_frequency())
5456 .finish()
5457 }
5458}
5459
5460impl TscInfo {
5461 pub fn denominator(&self) -> u32 {
5463 self.eax
5464 }
5465
5466 pub fn numerator(&self) -> u32 {
5470 self.ebx
5471 }
5472
5473 pub fn nominal_frequency(&self) -> u32 {
5477 self.ecx
5478 }
5479
5480 pub fn tsc_frequency(&self) -> Option<u64> {
5482 if self.nominal_frequency() == 0 || self.numerator() == 0 || self.denominator() == 0 {
5485 return None;
5486 }
5487
5488 Some(self.nominal_frequency() as u64 * self.numerator() as u64 / self.denominator() as u64)
5489 }
5490}
5491
5492pub struct ProcessorFrequencyInfo {
5497 eax: u32,
5498 ebx: u32,
5499 ecx: u32,
5500}
5501
5502impl ProcessorFrequencyInfo {
5503 pub fn processor_base_frequency(&self) -> u16 {
5505 get_bits(self.eax, 0, 15) as u16
5506 }
5507
5508 pub fn processor_max_frequency(&self) -> u16 {
5510 get_bits(self.ebx, 0, 15) as u16
5511 }
5512
5513 pub fn bus_frequency(&self) -> u16 {
5515 get_bits(self.ecx, 0, 15) as u16
5516 }
5517}
5518
5519impl fmt::Debug for ProcessorFrequencyInfo {
5520 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
5521 f.debug_struct("ProcessorFrequencyInfo")
5522 .field("processor_base_frequency", &self.processor_base_frequency())
5523 .field("processor_max_frequency", &self.processor_max_frequency())
5524 .field("bus_frequency", &self.bus_frequency())
5525 .finish()
5526 }
5527}
5528
5529#[derive(Clone)]
5534pub struct DatIter<R: CpuIdReader> {
5535 read: R,
5536 current: u32,
5537 count: u32,
5538}
5539
5540impl<R: CpuIdReader> Iterator for DatIter<R> {
5541 type Item = DatInfo;
5542
5543 fn next(&mut self) -> Option<DatInfo> {
5545 loop {
5546 if self.current > self.count {
5548 return None;
5549 }
5550
5551 let res = self
5552 .read
5553 .cpuid2(EAX_DETERMINISTIC_ADDRESS_TRANSLATION_INFO, self.current);
5554 self.current += 1;
5555
5556 if get_bits(res.edx, 0, 4) == 0 {
5558 continue;
5562 }
5563
5564 return Some(DatInfo {
5565 _eax: res.eax,
5566 ebx: res.ebx,
5567 ecx: res.ecx,
5568 edx: res.edx,
5569 });
5570 }
5571 }
5572}
5573
5574impl<R: CpuIdReader> Debug for DatIter<R> {
5575 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
5576 let mut debug = f.debug_list();
5577 self.clone().for_each(|ref item| {
5578 debug.entry(item);
5579 });
5580 debug.finish()
5581 }
5582}
5583
5584pub struct DatInfo {
5586 _eax: u32,
5587 ebx: u32,
5588 ecx: u32,
5589 edx: u32,
5590}
5591
5592impl DatInfo {
5593 check_bit_fn!(
5594 doc = "4K page size entries supported by this structure",
5595 has_4k_entries,
5596 ebx,
5597 0
5598 );
5599
5600 check_bit_fn!(
5601 doc = "2MB page size entries supported by this structure",
5602 has_2mb_entries,
5603 ebx,
5604 1
5605 );
5606
5607 check_bit_fn!(
5608 doc = "4MB page size entries supported by this structure",
5609 has_4mb_entries,
5610 ebx,
5611 2
5612 );
5613
5614 check_bit_fn!(
5615 doc = "1GB page size entries supported by this structure",
5616 has_1gb_entries,
5617 ebx,
5618 3
5619 );
5620
5621 check_bit_fn!(
5622 doc = "Fully associative structure",
5623 is_fully_associative,
5624 edx,
5625 8
5626 );
5627
5628 pub fn partitioning(&self) -> u8 {
5630 get_bits(self.ebx, 8, 10) as u8
5631 }
5632
5633 pub fn ways(&self) -> u16 {
5635 get_bits(self.ebx, 16, 31) as u16
5636 }
5637
5638 pub fn sets(&self) -> u32 {
5640 self.ecx
5641 }
5642
5643 pub fn cache_type(&self) -> DatType {
5645 match get_bits(self.edx, 0, 4) as u8 {
5646 0b00001 => DatType::DataTLB,
5647 0b00010 => DatType::InstructionTLB,
5648 0b00011 => DatType::UnifiedTLB,
5649 0b00000 => DatType::Null, 0b00100 => DatType::LoadOnly,
5651 0b00101 => DatType::StoreOnly,
5652 _ => DatType::Unknown,
5653 }
5654 }
5655
5656 pub fn cache_level(&self) -> u8 {
5658 get_bits(self.edx, 5, 7) as u8
5659 }
5660
5661 pub fn max_addressable_ids(&self) -> u16 {
5663 (get_bits(self.edx, 14, 25) + 1) as u16
5665 }
5666}
5667
5668impl Debug for DatInfo {
5669 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
5670 f.debug_struct("DatInfo")
5671 .field("has_4k_entries", &self.has_4k_entries())
5672 .field("has_2mb_entries", &self.has_2mb_entries())
5673 .field("has_4mb_entries", &self.has_4mb_entries())
5674 .field("has_1gb_entries", &self.has_1gb_entries())
5675 .field("is_fully_associative", &self.is_fully_associative())
5676 .finish()
5677 }
5678}
5679
5680#[derive(Eq, PartialEq, Debug)]
5682pub enum DatType {
5683 Null = 0b00000,
5685 DataTLB = 0b00001,
5686 InstructionTLB = 0b00010,
5687 UnifiedTLB = 0b00011,
5693 LoadOnly = 0b0100,
5694 StoreOnly = 0b0101,
5695 Unknown,
5696}
5697
5698impl fmt::Display for DatType {
5699 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
5700 let t = match self {
5701 DatType::Null => "invalid (0)",
5702 DatType::DataTLB => "Data TLB",
5703 DatType::InstructionTLB => "Instruction TLB",
5704 DatType::UnifiedTLB => "Unified TLB",
5705 DatType::LoadOnly => "Load Only",
5706 DatType::StoreOnly => "Store Only",
5707 DatType::Unknown => "Unknown",
5708 };
5709 f.write_str(t)
5710 }
5711}
5712
5713pub struct SoCVendorInfo<R: CpuIdReader> {
5718 read: R,
5719 eax: u32,
5721 ebx: u32,
5722 ecx: u32,
5723 edx: u32,
5724}
5725
5726impl<R: CpuIdReader> SoCVendorInfo<R> {
5727 pub fn get_soc_vendor_id(&self) -> u16 {
5728 get_bits(self.ebx, 0, 15) as u16
5729 }
5730
5731 pub fn get_project_id(&self) -> u32 {
5732 self.ecx
5733 }
5734
5735 pub fn get_stepping_id(&self) -> u32 {
5736 self.edx
5737 }
5738
5739 pub fn get_vendor_brand(&self) -> Option<SoCVendorBrand> {
5740 if self.eax >= 3 {
5742 let r1 = self.read.cpuid2(EAX_SOC_VENDOR_INFO, 1);
5743 let r2 = self.read.cpuid2(EAX_SOC_VENDOR_INFO, 2);
5744 let r3 = self.read.cpuid2(EAX_SOC_VENDOR_INFO, 3);
5745 Some(SoCVendorBrand { data: [r1, r2, r3] })
5746 } else {
5747 None
5748 }
5749 }
5750
5751 pub fn get_vendor_attributes(&self) -> Option<SoCVendorAttributesIter<R>> {
5752 if self.eax > 3 {
5753 Some(SoCVendorAttributesIter {
5754 read: self.read.clone(),
5755 count: self.eax,
5756 current: 3,
5757 })
5758 } else {
5759 None
5760 }
5761 }
5762}
5763
5764impl<R: CpuIdReader> fmt::Debug for SoCVendorInfo<R> {
5765 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
5766 f.debug_struct("SoCVendorInfo")
5767 .field("soc_vendor_id", &self.get_soc_vendor_id())
5768 .field("project_id", &self.get_project_id())
5769 .field("stepping_id", &self.get_stepping_id())
5770 .field("vendor_brand", &self.get_vendor_brand())
5771 .field("vendor_attributes", &self.get_vendor_attributes())
5772 .finish()
5773 }
5774}
5775
5776pub struct SoCVendorAttributesIter<R: CpuIdReader> {
5778 read: R,
5779 count: u32,
5780 current: u32,
5781}
5782
5783impl<R: CpuIdReader> fmt::Debug for SoCVendorAttributesIter<R> {
5784 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
5785 f.debug_struct("SocVendorAttributesIter")
5786 .field("count", &self.count)
5787 .field("current", &self.current)
5788 .finish()
5789 }
5790}
5791
5792impl<R: CpuIdReader> Iterator for SoCVendorAttributesIter<R> {
5793 type Item = CpuIdResult;
5794
5795 fn next(&mut self) -> Option<CpuIdResult> {
5797 if self.current > self.count {
5798 return None;
5799 }
5800 self.count += 1;
5801 Some(self.read.cpuid2(EAX_SOC_VENDOR_INFO, self.count))
5802 }
5803}
5804
5805#[derive(Debug, PartialEq, Eq)]
5807#[repr(C)]
5808pub struct SoCVendorBrand {
5809 data: [CpuIdResult; 3],
5810}
5811
5812impl SoCVendorBrand {
5813 pub fn as_str(&self) -> &str {
5815 let brand_string_start = self as *const SoCVendorBrand as *const u8;
5816 let slice = unsafe {
5817 slice::from_raw_parts(brand_string_start, size_of::<SoCVendorBrand>())
5819 };
5820 str::from_utf8(slice).unwrap_or("InvalidSoCVendorString")
5821 }
5822
5823 #[deprecated(
5824 since = "10.0.0",
5825 note = "Use idiomatic function name `as_str` instead"
5826 )]
5827 pub fn as_string(&self) -> &str {
5828 self.as_str()
5829 }
5830}
5831
5832impl fmt::Display for SoCVendorBrand {
5833 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
5834 write!(f, "{}", self.as_str())
5835 }
5836}
5837
5838pub struct HypervisorInfo<R: CpuIdReader> {
5843 read: R,
5844 res: CpuIdResult,
5845}
5846
5847impl<R: CpuIdReader> fmt::Debug for HypervisorInfo<R> {
5848 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
5849 f.debug_struct("HypervisorInfo")
5850 .field("identify", &self.identify())
5851 .field("tsc_frequency", &self.tsc_frequency())
5852 .field("apic_frequency", &self.apic_frequency())
5853 .finish()
5854 }
5855}
5856
5857#[derive(Debug, Eq, PartialEq)]
5859pub enum Hypervisor {
5860 Xen,
5861 VMware,
5862 HyperV,
5863 KVM,
5864 QEMU,
5867 Bhyve,
5868 QNX,
5869 ACRN,
5870 Unknown(u32, u32, u32),
5871}
5872
5873impl<R: CpuIdReader> HypervisorInfo<R> {
5874 pub fn identify(&self) -> Hypervisor {
5885 match (self.res.ebx, self.res.ecx, self.res.edx) {
5886 (0x61774d56, 0x4d566572, 0x65726177) => Hypervisor::VMware,
5888 (0x566e6558, 0x65584d4d, 0x4d4d566e) => Hypervisor::Xen,
5890 (0x7263694d, 0x666f736f, 0x76482074) => Hypervisor::HyperV,
5892 (0x4b4d564b, 0x564b4d56, 0x0000004d) => Hypervisor::KVM,
5894 (0x54474354, 0x43544743, 0x47435447) => Hypervisor::QEMU,
5897 (0x76796862, 0x68622065, 0x20657679) => Hypervisor::Bhyve,
5900 (0x56794842, 0x48422045, 0x20455679) => Hypervisor::Bhyve,
5904 (0x51584e51, 0x53424d56, 0x00004751) => Hypervisor::QNX,
5908 (0x4e524341, 0x4e524341, 0x4e524341) => Hypervisor::ACRN,
5910 (ebx, ecx, edx) => Hypervisor::Unknown(ebx, ecx, edx),
5911 }
5912 }
5913
5914 pub fn tsc_frequency(&self) -> Option<u32> {
5916 if self.res.eax >= 0x40000010 {
5919 let virt_tinfo = self.read.cpuid2(0x40000010, 0);
5920 Some(virt_tinfo.eax)
5921 } else {
5922 None
5923 }
5924 }
5925
5926 pub fn apic_frequency(&self) -> Option<u32> {
5928 if self.res.eax >= 0x40000010 {
5930 let virt_tinfo = self.read.cpuid2(0x40000010, 0);
5931 Some(virt_tinfo.ebx)
5932 } else {
5933 None
5934 }
5935 }
5936}
5937
5938#[cfg(doctest)]
5939mod test_readme {
5940 macro_rules! external_doc_test {
5941 ($x:expr) => {
5942 #[doc = $x]
5943 extern "C" {}
5944 };
5945 }
5946
5947 external_doc_test!(include_str!("../README.md"));
5948}