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
617pub const ADDRESS_SIZE_INFO: CpuidValue<0x8000_0008, 0, EAX, AddressSizeInfo> = CpuidValue::new();
623
624layout!({
625 pub struct AddressSizeInfo(u32);
627 {
628 let __ @ 31..24;
629 let guest_phys_addr_bits @ 23..16;
630 let linear_addr_bits @ 15..8;
631 let phys_addr_bits @ 7..0;
632 }
633});
634
635#[bitfield_repr(u8)]
637#[derive(Clone, Copy)]
638pub enum PerfTimestampCounterSize {
639 Bits40 = 0b00,
640 Bits48 = 0b01,
641 Bits56 = 0b10,
642 Bits64 = 0b11,
643}
644
645pub const EXTENDED_SIZE_INFO: CpuidValue<0x8000_0008, 0, ECX, ExtendedSizeInfo> = CpuidValue::new();
650
651layout!({
652 pub struct ExtendedSizeInfo(u32);
654 {
655 let __ @ 31..18;
656 let perf_tsc_size @ 17..16: PerfTimestampCounterSize;
657 let apic_id_size @ 15..12;
658 let __ @ 11..8;
659 let nc @ 7..0;
660 }
661});
662
663pub const EXTENDED_AMD_FEATURES_B: CpuidValue<0x8000_0008, 0, EBX, ExtendedAmdFeaturesB> =
669 CpuidValue::new();
670
671layout!({
672 pub struct ExtendedAmdFeaturesB(u32);
677 {
678 let __ @ 31..27;
679 let ssb_no @ 26;
680 let virt_ssbd @ 25;
681 let ssbd @ 24;
682 let __ @ 23..19;
683 let prefers_ibrs @ 18;
684 let stibp_always_on @ 17;
685 let ibrs_always_on @ 16;
686 let stibp @ 15;
687 let ibrs @ 14;
688 let __ @ 13;
689 let ibpb @ 12;
690 let __ @ 11..10;
691 let wbnoinvd @ 9;
692 let mcommit @ 8;
693 let __ @ 7..5;
694 let rdpru @ 4;
695 let __ @ 3;
696 let rstr_fp_err_ptrs @ 2;
697 let inst_ret_cnt_msr @ 1;
698 let clzero @ 0;
699 }
700});
701
702pub const EXTENDED_APIC_ID: CpuidValue<0x8000_001e, 0, EAX, ExtendedApicId> = CpuidValue::new();
706
707layout!({
708 pub struct ExtendedApicId(u32);
710 {
711 let x2apic_id @ 31..0;
712 }
713});
714
715pub const COMPUTE_UNIT_INFO: CpuidValue<0x8000_001e, 0, EBX, ComputeUnitInfo> = CpuidValue::new();
719
720layout!({
721 pub struct ComputeUnitInfo(u32);
723 {
724 let __ @ 31..16;
725 let threads_per_compute_unit @ 15..8;
726 let compute_unit_id @ 7..0;
727 }
728});
729
730pub const NODE_INFO: CpuidValue<0x8000_001e, 0, ECX, NodeInfo> = CpuidValue::new();
734
735layout!({
736 pub struct NodeInfo(u32);
738 {
739 let __ @ 31..11;
740 let nodes_per_package @ 10..8;
741 let node_id @ 7..0;
742 }
743});
744
745pub const VERSION_INFO: CpuidValue<0x1, 0x0, EAX, VersionInfo> = CpuidValue::new();
752
753#[bitfield_repr(u8)]
757#[derive(Clone, Copy)]
758pub enum IntelProcessorType {
759 OriginalOem = 0b00,
760 IntelOverdrive = 0b01,
761 Dual = 0b10,
762 Reserved = 0b11,
763}
764
765layout!({
766 pub struct VersionInfo(u32);
768 {
769 let __ @ 31..28;
770 let extended_family @ 27..20;
771 let extended_model @ 19..16;
772 let __ @ 15..14;
773 let intel_processor @ 13..12: IntelProcessorType;
774 let base_family @ 11..8;
775 let base_model @ 7..4;
776 let stepping @ 3..0;
777 }
778});
779
780impl VersionInfo {
781 pub fn family(self) -> u8 {
782 if self.base_family() == 0xf {
783 self.base_family() + self.extended_family()
784 } else {
785 self.base_family()
786 }
787 }
788
789 pub fn model(self) -> u8 {
790 if self.base_family() == 0x6 || self.base_family() == 0xf {
791 (self.extended_model() << 4) | self.base_model()
792 } else {
793 self.base_model()
794 }
795 }
796
797 pub fn microarchitecture(self, vendor: Vendor) -> Microarchitecture {
800 match vendor {
803 Vendor::Intel => {
804 match self.family() {
806 0x6 => match self.model() {
807 0x0f | 0x16 | 0x17 | 0x1d => Microarchitecture::IntelCore2,
813 0x1a | 0x1e | 0x1f | 0x2e => Microarchitecture::IntelNehalem,
818 0x25 | 0x2c | 0x2f => Microarchitecture::IntelWestmere,
822 0x2a | 0x2d => Microarchitecture::IntelSandyBridge,
825 0x3a | 0x3e => Microarchitecture::IntelIvyBridge,
828 0x3c | 0x3f | 0x45 | 0x46 => Microarchitecture::IntelHaswell,
833 0x3d | 0x47 | 0x56 | 0x4f => Microarchitecture::IntelBroadwell,
838 0x4e | 0x5e | 0x8e | 0x9e | 0xa5 => Microarchitecture::IntelSkylake,
845 0x55 => Microarchitecture::IntelSkylakeServer,
847 0x66 => Microarchitecture::IntelCannonLake,
849 0x6a | 0x6c | 0x7d | 0x7e => Microarchitecture::IntelIceLake,
854 0x8c | 0x8d => Microarchitecture::IntelTigerLake,
857 0x97 | 0x9a => Microarchitecture::IntelAlderLake,
860 0xb7 => Microarchitecture::IntelRaptorLake,
862
863 0x1c | 0x26 => Microarchitecture::IntelBonnell,
867 0x27 | 0x35 | 0x36 => Microarchitecture::IntelSaltwell,
871 0x37 | 0x4a | 0x4d | 0x5a | 0x5d => Microarchitecture::IntelSilvermont,
877 0x4c => Microarchitecture::IntelAirmont,
879 0x5c | 0x5f => Microarchitecture::IntelGoldmont,
882 0x7a => Microarchitecture::IntelGoldmontPlus,
884 0x8a | 0x96 | 0x9c => Microarchitecture::IntelTremont,
888 _ => Microarchitecture::Unknown,
889 },
890 _ => Microarchitecture::Unknown,
891 }
892 }
893 Vendor::Amd => {
894 match self.family() {
896 0x15 => Microarchitecture::AmdFamilyBulldozer,
898 0x16 => Microarchitecture::AmdFamilyJaguar,
900 0x17 => Microarchitecture::AmdFamilyZen,
902 0x19 => Microarchitecture::AmdFamilyZen3,
904 _ => Microarchitecture::Unknown,
905 }
906 }
907 Vendor::Unknown => Microarchitecture::Unknown,
908 }
909 }
910}
911
912#[derive(Clone, Debug, Eq, PartialEq)]
916pub enum Microarchitecture {
917 Unknown,
918
919 IntelCore2,
921 IntelNehalem,
922 IntelWestmere,
923 IntelSandyBridge,
924 IntelIvyBridge,
925 IntelHaswell,
926 IntelBroadwell,
927 IntelSkylake,
929 IntelSkylakeServer,
931 IntelCannonLake,
933 IntelIceLake,
934 IntelTigerLake,
935 IntelAlderLake,
936 IntelRaptorLake,
937
938 IntelBonnell,
940 IntelSaltwell,
941 IntelSilvermont,
942 IntelAirmont,
943 IntelGoldmont,
944 IntelGoldmontPlus,
945 IntelTremont,
946
947 AmdFamilyBulldozer,
950 AmdFamilyJaguar,
952 AmdFamilyZen,
954 AmdFamilyZen3,
956}
957
958impl fmt::Display for Microarchitecture {
959 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
960 f.write_str(match self {
961 Self::Unknown => "Unknown",
962 Self::IntelCore2 => "Intel Core 2",
963 Self::IntelNehalem => "Intel Nehalem",
964 Self::IntelWestmere => "Intel Westmere",
965 Self::IntelSandyBridge => "Intel Sandy Bridge",
966 Self::IntelIvyBridge => "Intel Ivy Bridge",
967 Self::IntelBroadwell => "Intel Broadwell",
968 Self::IntelHaswell => "Intel Haswell",
969 Self::IntelSkylake => "Intel Skylake",
970 Self::IntelSkylakeServer => "Intel Skylake (server)",
971 Self::IntelCannonLake => "Intel Cannon Lake",
972 Self::IntelIceLake => "Intel Ice Lake",
973 Self::IntelTigerLake => "Intel Tiger Lake",
974 Self::IntelAlderLake => "Intel Alder Lake",
975 Self::IntelRaptorLake => "Intel Raptor Lake",
976 Self::IntelBonnell => "Intel Bonnell",
977 Self::IntelSaltwell => "Intel Saltwell",
978 Self::IntelSilvermont => "Intel Silvermont",
979 Self::IntelAirmont => "Intel Airmont",
980 Self::IntelGoldmont => "Intel Goldmont",
981 Self::IntelGoldmontPlus => "Intel Goldmont Plus",
982 Self::IntelTremont => "Intel Tremont",
983 Self::AmdFamilyBulldozer => "AMD Bulldozer",
984 Self::AmdFamilyJaguar => "AMD Jaguar",
985 Self::AmdFamilyZen => "AMD Zen 1-2",
986 Self::AmdFamilyZen3 => "AMD Zen 3-4",
987 })
988 }
989}
990
991#[cfg(test)]
992mod tests {
993 use super::*;
994
995 #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
997 #[test]
998 fn feature_detection() {
999 use regio::x86::DirectCpuid;
1000
1001 let vendor = VendorString::from_cpuid(DirectCpuid {});
1002 println!("Vendor string: {}", vendor.as_str().unwrap_or("invalid vendor string"));
1003 }
1004
1005 #[test]
1006 fn amd_vendor_string() {
1007 use regio::testing::x86::FakeCpuid;
1008
1009 let mut cpuid = FakeCpuid::new();
1011 cpuid
1012 .set(VENDOR_STRING_B, 0x6874_7541)
1013 .set(VENDOR_STRING_C, 0x444d_4163)
1014 .set(VENDOR_STRING_D, 0x6974_6e65);
1015 let vendor_str = VendorString::from_cpuid(&cpuid);
1016 assert_eq!(vendor_str, VendorString::AMD);
1017 }
1018
1019 #[test]
1020 fn address_size_info() {
1021 let info = AddressSizeInfo::from(0x002b_3027);
1022 assert_eq!(info.phys_addr_bits(), 0x27);
1023 assert_eq!(info.linear_addr_bits(), 0x30);
1024 assert_eq!(info.guest_phys_addr_bits(), 0x2b);
1025 }
1026}