1use core::fmt;
6use core::str::Utf8Error;
7
8use bitrs::{bitfield_repr, layout};
9use regio::x86::{Cpuid, CpuidValue, EAX, EBX, ECX, EDX};
10
11use super::Vendor;
12
13pub const MAX_LEAF: CpuidValue<0x0, 0x0, EAX, u32> = CpuidValue::new();
18
19pub const VENDOR_STRING_B: CpuidValue<0x0, 0x0, EBX, u32> = CpuidValue::new();
24
25pub const VENDOR_STRING_C: CpuidValue<0x0, 0x0, ECX, u32> = CpuidValue::new();
30
31pub const VENDOR_STRING_D: CpuidValue<0x0, 0x0, EDX, u32> = CpuidValue::new();
36
37#[derive(Clone, Copy, Debug, Eq, PartialEq)]
39pub struct VendorString([u8; 12]);
40
41impl VendorString {
42 pub const INTEL: Self = Self(*b"GenuineIntel");
44
45 pub const AMD: Self = Self(*b"AuthenticAMD");
47
48 pub fn from_cpuid(cpuid: impl Cpuid) -> Self {
50 let ebx = cpuid.read(VENDOR_STRING_B).to_le_bytes();
51 let ecx = cpuid.read(VENDOR_STRING_C).to_le_bytes();
52 let edx = cpuid.read(VENDOR_STRING_D).to_le_bytes();
53 Self([
54 ebx[0], ebx[1], ebx[2], ebx[3], edx[0], edx[1], edx[2], edx[3], ecx[0], ecx[1], ecx[2], ecx[3], ])
58 }
59
60 pub fn vendor(&self) -> Vendor {
65 match *self {
66 Self::INTEL => Vendor::Intel,
67 Self::AMD => Vendor::Amd,
68 _ => Vendor::Unknown,
69 }
70 }
71
72 pub fn as_str(&self) -> Result<&str, Utf8Error> {
73 str::from_utf8(&self.0)
74 }
75}
76
77pub const PROCESSOR_INFO: CpuidValue<0x1, 0x0, EBX, ProcessorInfo> = CpuidValue::new();
82
83layout!({
84 pub struct ProcessorInfo(u32);
86 {
87 let initial_apic_id @ 31..24;
88 let max_logical_processors @ 23..16;
89 let clflush_size @ 15..8;
90 let brand_index @ 7..0;
91 }
92});
93
94impl ProcessorInfo {
95 pub fn cache_line_size_bytes(&self) -> usize {
96 self.clflush_size() as usize * 8
97 }
98}
99
100pub const FEATURE_FLAGS_C: CpuidValue<0x1, 0x0, ECX, FeatureFlagsC> = CpuidValue::new();
105
106layout!({
107 pub struct FeatureFlagsC(u32);
109 {
110 let hypervisor @ 31;
111 let rdrand @ 30;
112 let f16c @ 29;
113 let avx @ 28;
114 let osxsave @ 27;
115 let xsave @ 26;
116 let aes @ 25;
117 let tsc_deadline @ 24;
118 let popcnt @ 23;
119 let movbe @ 22;
120 let x2apic @ 21;
121 let sse4_2 @ 20;
122 let sse4_1 @ 19;
123 let dca @ 18;
124 let pcid @ 17;
125 let __ @ 16;
126 let pdcm @ 15;
127 let xtpr @ 14;
128 let cmpxchg16b @ 13;
129 let fma @ 12;
130 let sdbg @ 11;
131 let cnxt_id @ 10;
132 let ssse3 @ 9;
133 let tm2 @ 8;
134 let eist @ 7;
135 let smx @ 6;
136 let vmx @ 5;
137 let ds_cpl @ 4;
138 let monitor @ 3;
139 let dtes64 @ 2;
140 let pclmulqdq @ 1;
141 let sse3 @ 0;
142 }
143});
144
145pub const FEATURE_FLAGS_D: CpuidValue<0x1, 0x0, EDX, FeatureFlagsD> = CpuidValue::new();
150
151layout!({
152 pub struct FeatureFlagsD(u32);
154 {
155 let pbe @ 31;
156 let __ @ 30;
157 let tm @ 29;
158 let htt @ 28;
159 let ss @ 27;
160 let sse2 @ 26;
161 let sse @ 25;
162 let fxsr @ 24;
163 let mmx @ 23;
164 let acpi @ 22;
165 let ds @ 21;
166 let __ @ 20;
167 let clfsh @ 19;
168 let psn @ 18;
169 let pse36 @ 17;
170 let pat @ 16;
171 let cmov @ 15;
172 let mca @ 14;
173 let pge @ 13;
174 let mtrr @ 12;
175 let sep @ 11;
176 let __ @ 10;
177 let apic @ 9;
178 let cx8 @ 8;
179 let mce @ 7;
180 let pae @ 6;
181 let msr @ 5;
182 let tsc @ 4;
183 let pse @ 3;
184 let de @ 2;
185 let vme @ 1;
186 let fpu @ 0;
187 }
188});
189
190pub const EXTENDED_FEATURES_B: CpuidValue<0x7, 0x0, EBX, ExtendedFeatureFlagsB> = CpuidValue::new();
196
197layout!({
198 pub struct ExtendedFeatureFlagsB(u32);
200 {
201 let avx512vl @ 31;
202 let avx512bw @ 30;
203 let sha @ 29;
204 let avx512cd @ 28;
205 let avx512er @ 27;
206 let avx512pf @ 26;
207 let intel_pt @ 25;
208 let clwb @ 24;
209 let clflushopt @ 23;
210 let __ @ 22;
211 let avx512_ifma @ 21;
212 let smap @ 20;
213 let adx @ 19;
214 let rdseed @ 18;
215 let avx512dq @ 17;
216 let avx512f @ 16;
217 let rdt_a @ 15;
218 let mpx @ 14;
219 let fpu_cs_ds_deprecated @ 13;
220 let rdt_m @ 12;
221 let rtm @ 11;
222 let invpcid @ 10;
223 let erms @ 9;
224 let bmi2 @ 8;
225 let smep @ 7;
226 let fdp_excptn_only_x87 @ 6;
227 let avx2 @ 5;
228 let hle @ 4;
229 let bmi1 @ 3;
230 let sgx @ 2;
231 let tsc_adjust @ 1;
232 let fsgsbase @ 0;
233 }
234});
235
236pub const EXTENDED_FEATURES_C: CpuidValue<0x7, 0x0, ECX, ExtendedFeatureFlagsC> = CpuidValue::new();
242
243layout!({
244 pub struct ExtendedFeatureFlagsC(u32);
246 {
247 let pks @ 31;
248 let sgx_lc @ 30;
249 let __ @ 29;
250 let movdir64b @ 28;
251 let movdiri @ 27;
252 let __ @ 26;
253 let cldemote @ 25;
254 let __ @ 24;
255 let kl @ 23;
256 let rdpid @ 22;
257 let __ @ 21..17;
260 let la57 @ 16;
261 let __ @ 15;
262 let avx512_vpopcntdq @ 14;
263 let tme_en @ 13;
264 let avx512_bitalg @ 12;
265 let avx512_vnni @ 11;
266 let vpclmulqdq @ 10;
267 let vaes @ 9;
268 let gfni @ 8;
269 let cet_ss @ 7;
270 let avx512_vbmi2 @ 6;
271 let waitpkg @ 5;
272 let ospke @ 4;
273 let pku @ 3;
274 let umip @ 2;
275 let avx512_vbmi @ 1;
276 let prefetchwt1 @ 0;
277 }
278});
279
280pub const EXTENDED_FEATURES_D: CpuidValue<0x7, 0x0, EDX, ExtendedFeatureFlagsD> = CpuidValue::new();
286
287layout!({
288 pub struct ExtendedFeatureFlagsD(u32);
290 {
291 let ssbd @ 31;
292 let ia32_core_capabilities @ 30;
293 let ia32_arch_capabilities @ 29;
294 let l1d_flush @ 28;
295 let stibp @ 27;
296 let ibrs_ibpb @ 26;
297 let __ @ 25..21;
298 let cet_ibt @ 20;
299 let __ @ 19;
300 let pconfig @ 18;
301 let __ @ 17..16;
302 let hybrid @ 15;
303 let serialize @ 14;
304 let __ @ 13..11;
305 let md_clear @ 10;
306 let __ @ 9;
307 let avx512_vp2intersect @ 8;
308 let __ @ 7..5;
309 let fsrm @ 4;
310 let avx512_4fmaps @ 3;
311 let avx512_4vnniw @ 2;
312 let __ @ 1..0;
313 }
314});
315
316#[bitfield_repr(u8)]
318#[derive(Clone, Copy)]
319pub enum CacheType {
320 Null = 0,
321 Data = 1,
322 Instruction = 2,
323 Unified = 3,
324}
325
326pub const INTEL_CACHE_TOPOLOGY_A: CpuidValue<0x4, 0, EAX, CacheTopologyA> = CpuidValue::new();
333
334pub const AMD_CACHE_TOPOLOGY_A: CpuidValue<0x8000_001d, 0, EAX, CacheTopologyA> = CpuidValue::new();
338
339layout!({
340 pub struct CacheTopologyA(u32);
342 {
343 let max_cores @ 31..26; let max_sharing_logical_processors @ 25..14;
345 let __ @ 13..10;
346 let fully_associative @ 9;
347 let self_initializing @ 8;
348 let cache_level @ 7..5;
349 let cache_type @ 4..0: CacheType;
350 }
351});
352
353layout!({
354 pub struct CacheTopologyB(u32);
356 {
357 let ways @ 31..22;
358 let physical_line_partitions @ 21..12;
359 let system_coherency_line_size @ 11..0;
360 }
361});
362
363layout!({
364 pub struct CacheTopologyC(u32);
366 {
367 let sets @ 31..0;
368 }
369});
370
371layout!({
372 pub struct CacheTopologyD(u32);
374 {
375 let __ @ 31..3;
376 let complex_cache_indexing @ 2;
377 let inclusive @ 1;
378 let wbinvd @ 0;
379 }
380});
381
382pub const AMD_L1_DATA_CACHE_INFO: CpuidValue<0x8000_0005, 0, ECX, AmdL1CacheInformation> =
386 CpuidValue::new();
387
388pub const AMD_L1_INSTRUCTION_CACHE_INFO: CpuidValue<0x8000_0005, 0, EDX, AmdL1CacheInformation> =
392 CpuidValue::new();
393
394layout!({
395 pub struct AmdL1CacheInformation(u32);
398 {
399 let size_kb @ 31..24;
400 let assoc @ 23..16;
401 let lines_per_tag @ 15..8;
402 let line_size @ 7..0;
403 }
404});
405
406impl AmdL1CacheInformation {
407 pub const FULLY_ASSOCIATIVE: u8 = 0xff;
408
409 pub fn ways_of_associativity(&self) -> usize {
410 if self.assoc() == Self::FULLY_ASSOCIATIVE { 0 } else { self.assoc() as usize }
411 }
412
413 pub fn fully_associative(&self) -> Option<bool> {
414 match self.assoc() {
415 0 => None,
416 Self::FULLY_ASSOCIATIVE => Some(true),
417 _ => Some(false),
418 }
419 }
420}
421
422#[bitfield_repr(u8)]
424#[derive(Clone, Copy)]
425pub enum AmdL2L3Associativity {
426 Disabled = 0x0,
427 DirectMapped = 0x1,
428 Ways2 = 0x2,
429 Ways3 = 0x3,
430 Ways4 = 0x4,
431 Ways6 = 0x5,
432 Ways8 = 0x6,
433 Ways16 = 0x8,
435 SeeLeaf0x8000001d = 0x9,
436 Ways32 = 0xa,
437 Ways48 = 0xb,
438 Ways64 = 0xc,
439 Ways96 = 0xd,
440 Ways128 = 0xe,
441 FullyAssociative = 0xf,
442}
443
444impl AmdL2L3Associativity {
445 pub fn ways_of_associativity(&self) -> usize {
447 match self {
448 Self::Disabled | Self::SeeLeaf0x8000001d | Self::FullyAssociative => 0,
449 Self::DirectMapped => 1,
450 Self::Ways2 => 2,
451 Self::Ways3 => 3,
452 Self::Ways4 => 4,
453 Self::Ways6 => 6,
454 Self::Ways8 => 8,
455 Self::Ways16 => 16,
456 Self::Ways32 => 32,
457 Self::Ways48 => 48,
458 Self::Ways64 => 64,
459 Self::Ways96 => 96,
460 Self::Ways128 => 128,
461 }
462 }
463
464 pub fn fully_associative(&self) -> Option<bool> {
466 match self {
467 Self::Disabled => None,
468 Self::FullyAssociative => Some(true),
469 _ => Some(false),
470 }
471 }
472}
473
474pub const AMD_L2_CACHE_INFO: CpuidValue<0x8000_0006, 0, ECX, AmdL2CacheInformation> =
478 CpuidValue::new();
479
480layout!({
481 pub struct AmdL2CacheInformation(u32);
483 {
484 let size_kb @ 31..16;
485 let assoc @ 15..12: AmdL2L3Associativity;
486 let lines_per_tag @ 11..8;
487 let line_size @ 7..0;
488 }
489});
490
491impl AmdL2CacheInformation {
492 pub fn ways_of_associativity(&self) -> usize {
493 self.assoc().ways_of_associativity()
494 }
495
496 pub fn fully_associative(&self) -> Option<bool> {
497 self.assoc().fully_associative()
498 }
499}
500
501pub const AMD_L3_CACHE_INFO: CpuidValue<0x8000_0006, 0, EDX, AmdL3CacheInformation> =
505 CpuidValue::new();
506
507layout!({
508 pub struct AmdL3CacheInformation(u32);
510 {
511 let size @ 31..18;
512 let __ @ 17..16;
513 let assoc @ 15..12: AmdL2L3Associativity;
514 let lines_per_tag @ 11..8;
515 let line_size @ 7..0;
516 }
517});
518
519impl AmdL3CacheInformation {
520 pub fn ways_of_associativity(&self) -> usize {
521 self.assoc().ways_of_associativity()
522 }
523
524 pub fn fully_associative(&self) -> Option<bool> {
525 self.assoc().fully_associative()
526 }
527}
528
529#[bitfield_repr(u8)]
531#[derive(Clone, Copy)]
532pub enum TopologyLevelType {
533 Invalid = 0,
534 Smt = 1,
535 Core = 2,
536 Module = 3,
537 Tile = 4,
538 Die = 5,
539}
540
541layout!({
542 pub struct TopologyEnumerationA(u32);
544 {
545 let __ @ 31..5;
546 let next_level_apic_id_shift @ 4..0;
547 }
548});
549
550layout!({
551 pub struct TopologyEnumerationB(u32);
553 {
554 let __ @ 31..16;
555 let num_logical_processors @ 15..0;
556 }
557});
558
559layout!({
560 pub struct TopologyEnumerationC(u32);
562 {
563 let __ @ 31..16;
564 let level_type @ 15..8: TopologyLevelType;
565 let level_number @ 7..0;
566 }
567});
568
569layout!({
570 pub struct TopologyEnumerationD(u32);
572 {
573 let x2apic_id @ 31..0;
574 }
575});
576
577pub const V1_TOPOLOGY_A: CpuidValue<0xb, 0, EAX, TopologyEnumerationA> = CpuidValue::new();
581
582pub const V1_TOPOLOGY_B: CpuidValue<0xb, 0, EBX, TopologyEnumerationB> = CpuidValue::new();
586
587pub const V1_TOPOLOGY_C: CpuidValue<0xb, 0, ECX, TopologyEnumerationC> = CpuidValue::new();
591
592pub const V1_TOPOLOGY_D: CpuidValue<0xb, 0, EDX, TopologyEnumerationD> = CpuidValue::new();
596
597pub const V2_TOPOLOGY_A: CpuidValue<0x1f, 0, EAX, TopologyEnumerationA> = CpuidValue::new();
601
602pub const V2_TOPOLOGY_B: CpuidValue<0x1f, 0, EBX, TopologyEnumerationB> = CpuidValue::new();
606
607pub const V2_TOPOLOGY_C: CpuidValue<0x1f, 0, ECX, TopologyEnumerationC> = CpuidValue::new();
611
612pub const V2_TOPOLOGY_D: CpuidValue<0x1f, 0, EDX, TopologyEnumerationD> = CpuidValue::new();
616
617#[bitfield_repr(u8)]
619#[derive(Clone, Copy)]
620pub enum PerfTimestampCounterSize {
621 Bits40 = 0b00,
622 Bits48 = 0b01,
623 Bits56 = 0b10,
624 Bits64 = 0b11,
625}
626
627pub const EXTENDED_SIZE_INFO: CpuidValue<0x8000_0008, 0, ECX, ExtendedSizeInfo> = CpuidValue::new();
632
633layout!({
634 pub struct ExtendedSizeInfo(u32);
636 {
637 let __ @ 31..18;
638 let perf_tsc_size @ 17..16: PerfTimestampCounterSize;
639 let apic_id_size @ 15..12;
640 let __ @ 11..8;
641 let nc @ 7..0;
642 }
643});
644
645pub const EXTENDED_AMD_FEATURES_B: CpuidValue<0x8000_0008, 0, EBX, ExtendedAmdFeaturesB> =
651 CpuidValue::new();
652
653layout!({
654 pub struct ExtendedAmdFeaturesB(u32);
659 {
660 let __ @ 31..27;
661 let ssb_no @ 26;
662 let virt_ssbd @ 25;
663 let ssbd @ 24;
664 let __ @ 23..19;
665 let prefers_ibrs @ 18;
666 let stibp_always_on @ 17;
667 let ibrs_always_on @ 16;
668 let stibp @ 15;
669 let ibrs @ 14;
670 let __ @ 13;
671 let ibpb @ 12;
672 let __ @ 11..10;
673 let wbnoinvd @ 9;
674 let mcommit @ 8;
675 let __ @ 7..5;
676 let rdpru @ 4;
677 let __ @ 3;
678 let rstr_fp_err_ptrs @ 2;
679 let inst_ret_cnt_msr @ 1;
680 let clzero @ 0;
681 }
682});
683
684pub const EXTENDED_APIC_ID: CpuidValue<0x8000_001e, 0, EAX, ExtendedApicId> = CpuidValue::new();
688
689layout!({
690 pub struct ExtendedApicId(u32);
692 {
693 let x2apic_id @ 31..0;
694 }
695});
696
697pub const COMPUTE_UNIT_INFO: CpuidValue<0x8000_001e, 0, EBX, ComputeUnitInfo> = CpuidValue::new();
701
702layout!({
703 pub struct ComputeUnitInfo(u32);
705 {
706 let __ @ 31..16;
707 let threads_per_compute_unit @ 15..8;
708 let compute_unit_id @ 7..0;
709 }
710});
711
712pub const NODE_INFO: CpuidValue<0x8000_001e, 0, ECX, NodeInfo> = CpuidValue::new();
716
717layout!({
718 pub struct NodeInfo(u32);
720 {
721 let __ @ 31..11;
722 let nodes_per_package @ 10..8;
723 let node_id @ 7..0;
724 }
725});
726
727pub const VERSION_INFO: CpuidValue<0x1, 0x0, EAX, VersionInfo> = CpuidValue::new();
734
735#[bitfield_repr(u8)]
739#[derive(Clone, Copy)]
740pub enum IntelProcessorType {
741 OriginalOem = 0b00,
742 IntelOverdrive = 0b01,
743 Dual = 0b10,
744 Reserved = 0b11,
745}
746
747layout!({
748 pub struct VersionInfo(u32);
750 {
751 let __ @ 31..28;
752 let extended_family @ 27..20;
753 let extended_model @ 19..16;
754 let __ @ 15..14;
755 let intel_processor @ 13..12: IntelProcessorType;
756 let base_family @ 11..8;
757 let base_model @ 7..4;
758 let stepping @ 3..0;
759 }
760});
761
762impl VersionInfo {
763 pub fn family(self) -> u8 {
764 if self.base_family() == 0xf {
765 self.base_family() + self.extended_family()
766 } else {
767 self.base_family()
768 }
769 }
770
771 pub fn model(self) -> u8 {
772 if self.base_family() == 0x6 || self.base_family() == 0xf {
773 (self.extended_model() << 4) | self.base_model()
774 } else {
775 self.base_model()
776 }
777 }
778
779 pub fn microarchitecture(self, vendor: Vendor) -> Microarchitecture {
782 match vendor {
785 Vendor::Intel => {
786 match self.family() {
788 0x6 => match self.model() {
789 0x0f | 0x16 | 0x17 | 0x1d => Microarchitecture::IntelCore2,
795 0x1a | 0x1e | 0x1f | 0x2e => Microarchitecture::IntelNehalem,
800 0x25 | 0x2c | 0x2f => Microarchitecture::IntelWestmere,
804 0x2a | 0x2d => Microarchitecture::IntelSandyBridge,
807 0x3a | 0x3e => Microarchitecture::IntelIvyBridge,
810 0x3c | 0x3f | 0x45 | 0x46 => Microarchitecture::IntelHaswell,
815 0x3d | 0x47 | 0x56 | 0x4f => Microarchitecture::IntelBroadwell,
820 0x4e | 0x5e | 0x8e | 0x9e | 0xa5 => Microarchitecture::IntelSkylake,
827 0x55 => Microarchitecture::IntelSkylakeServer,
829 0x66 => Microarchitecture::IntelCannonLake,
831 0x6a | 0x6c | 0x7d | 0x7e => Microarchitecture::IntelIceLake,
836 0x8c | 0x8d => Microarchitecture::IntelTigerLake,
839 0x97 | 0x9a => Microarchitecture::IntelAlderLake,
842 0xb7 => Microarchitecture::IntelRaptorLake,
844
845 0x1c | 0x26 => Microarchitecture::IntelBonnell,
849 0x27 | 0x35 | 0x36 => Microarchitecture::IntelSaltwell,
853 0x37 | 0x4a | 0x4d | 0x5a | 0x5d => Microarchitecture::IntelSilvermont,
859 0x4c => Microarchitecture::IntelAirmont,
861 0x5c | 0x5f => Microarchitecture::IntelGoldmont,
864 0x7a => Microarchitecture::IntelGoldmontPlus,
866 0x8a | 0x96 | 0x9c => Microarchitecture::IntelTremont,
870 _ => Microarchitecture::Unknown,
871 },
872 _ => Microarchitecture::Unknown,
873 }
874 }
875 Vendor::Amd => {
876 match self.family() {
878 0x15 => Microarchitecture::AmdFamilyBulldozer,
880 0x16 => Microarchitecture::AmdFamilyJaguar,
882 0x17 => Microarchitecture::AmdFamilyZen,
884 0x19 => Microarchitecture::AmdFamilyZen3,
886 _ => Microarchitecture::Unknown,
887 }
888 }
889 Vendor::Unknown => Microarchitecture::Unknown,
890 }
891 }
892}
893
894#[derive(Clone, Debug, Eq, PartialEq)]
898pub enum Microarchitecture {
899 Unknown,
900
901 IntelCore2,
903 IntelNehalem,
904 IntelWestmere,
905 IntelSandyBridge,
906 IntelIvyBridge,
907 IntelHaswell,
908 IntelBroadwell,
909 IntelSkylake,
911 IntelSkylakeServer,
913 IntelCannonLake,
915 IntelIceLake,
916 IntelTigerLake,
917 IntelAlderLake,
918 IntelRaptorLake,
919
920 IntelBonnell,
922 IntelSaltwell,
923 IntelSilvermont,
924 IntelAirmont,
925 IntelGoldmont,
926 IntelGoldmontPlus,
927 IntelTremont,
928
929 AmdFamilyBulldozer,
932 AmdFamilyJaguar,
934 AmdFamilyZen,
936 AmdFamilyZen3,
938}
939
940impl fmt::Display for Microarchitecture {
941 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
942 f.write_str(match self {
943 Self::Unknown => "Unknown",
944 Self::IntelCore2 => "Intel Core 2",
945 Self::IntelNehalem => "Intel Nehalem",
946 Self::IntelWestmere => "Intel Westmere",
947 Self::IntelSandyBridge => "Intel Sandy Bridge",
948 Self::IntelIvyBridge => "Intel Ivy Bridge",
949 Self::IntelBroadwell => "Intel Broadwell",
950 Self::IntelHaswell => "Intel Haswell",
951 Self::IntelSkylake => "Intel Skylake",
952 Self::IntelSkylakeServer => "Intel Skylake (server)",
953 Self::IntelCannonLake => "Intel Cannon Lake",
954 Self::IntelIceLake => "Intel Ice Lake",
955 Self::IntelTigerLake => "Intel Tiger Lake",
956 Self::IntelAlderLake => "Intel Alder Lake",
957 Self::IntelRaptorLake => "Intel Raptor Lake",
958 Self::IntelBonnell => "Intel Bonnell",
959 Self::IntelSaltwell => "Intel Saltwell",
960 Self::IntelSilvermont => "Intel Silvermont",
961 Self::IntelAirmont => "Intel Airmont",
962 Self::IntelGoldmont => "Intel Goldmont",
963 Self::IntelGoldmontPlus => "Intel Goldmont Plus",
964 Self::IntelTremont => "Intel Tremont",
965 Self::AmdFamilyBulldozer => "AMD Bulldozer",
966 Self::AmdFamilyJaguar => "AMD Jaguar",
967 Self::AmdFamilyZen => "AMD Zen 1-2",
968 Self::AmdFamilyZen3 => "AMD Zen 3-4",
969 })
970 }
971}
972
973#[cfg(test)]
974mod tests {
975 use super::*;
976
977 #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
979 #[test]
980 fn feature_detection() {
981 use regio::x86::DirectCpuid;
982
983 let vendor = VendorString::from_cpuid(DirectCpuid {});
984 println!("Vendor string: {}", vendor.as_str().unwrap_or("invalid vendor string"));
985 }
986
987 #[test]
988 fn amd_vendor_string() {
989 use regio::testing::x86::FakeCpuid;
990
991 let mut cpuid = FakeCpuid::new();
993 cpuid
994 .set(VENDOR_STRING_B, 0x6874_7541)
995 .set(VENDOR_STRING_C, 0x444d_4163)
996 .set(VENDOR_STRING_D, 0x6974_6e65);
997 let vendor_str = VendorString::from_cpuid(&cpuid);
998 assert_eq!(vendor_str, VendorString::AMD);
999 }
1000}