1#![cfg_attr(not(cpuid_available), allow(dead_code))]
2
3use std::{fmt, slice, str};
18use std::ops::Deref;
19
20#[repr(u32)]
21enum RequestType {
22 BasicInformation = 0x00000000,
23 VersionInformation = 0x00000001,
24 ThermalPowerManagementInformation = 0x00000006,
25 StructuredExtendedInformation = 0x00000007,
26 ExtendedTopologyEnumeration = 0x0000000B,
27 ProcessorExtendedState = 0x0000000D,
28 ExtendedFunctionInformation = 0x80000000,
29 ExtendedProcessorSignature = 0x80000001,
30 BrandString1 = 0x80000002,
31 BrandString2 = 0x80000003,
32 BrandString3 = 0x80000004,
33 CacheLine = 0x80000006,
35 TimeStampCounter = 0x80000007,
36 PhysicalAddressSize = 0x80000008,
37}
38
39fn cpuid(code: RequestType) -> (u32, u32, u32, u32) {
40 cpuid_ext(code, 0x00000000)
41}
42
43#[cfg(engine_std)]
44fn cpuid_ext(code: RequestType, code2: u32) -> (u32, u32, u32, u32) {
45 #[cfg(target_arch = "x86_64")]
46 use std::arch::x86_64::__cpuid_count;
47 #[cfg(target_arch = "x86")]
48 use std::arch::x86::__cpuid_count;
49
50 let r = unsafe { __cpuid_count(code as u32, code2) };
51 (r.eax, r.ebx, r.ecx, r.edx)
52}
53
54#[cfg(engine_c)]
55fn cpuid_ext(code: RequestType, code2: u32) -> (u32, u32, u32, u32) {
56 extern {
57 fn __cupid_cpuid_shim_0_6(code: u32, code2: u32, output: *mut u32);
63 }
64
65 let mut ret = [0; 4];
66
67 unsafe {
68 __cupid_cpuid_shim_0_6(code as u32, code2, ret.as_mut_ptr());
69 }
70
71 (ret[0], ret[1], ret[2], ret[3])
72}
73
74#[cfg(not(cpuid_available))]
75fn cpuid_ext(_code: RequestType, _code2: u32) -> (u32, u32, u32, u32) {
76 unreachable!();
77}
78
79pub fn master() -> Option<Master> {
81 #[cfg(cpuid_available)] {
82 Some(Master::new())
83 }
84 #[cfg(not(cpuid_available))] {
85 None
86 }
87}
88
89fn bits_of(val: u32, start_bit: u8, end_bit: u8) -> u32 {
92 let mut silly = 0;
93
94 for _ in start_bit..end_bit+1 {
95 silly <<= 1;
96 silly |= 1;
97 }
98
99 (val >> start_bit) & silly
100}
101
102fn as_bytes(v: &u32) -> &[u8] {
103 let start = v as *const u32 as *const u8;
104 unsafe { slice::from_raw_parts(start, 4) }
106}
107
108macro_rules! bit {
109 ($reg:ident, {$($idx:expr => $name:ident),+}) => {
110 $(pub fn $name(self) -> bool {
111 ((self.$reg >> $idx) & 1) != 0
112 })+
113 }
114}
115
116macro_rules! dump {
117 ($me:expr, $f: expr, $sname:expr, {$($name:ident),+}) => {
118 $f.debug_struct($sname)
119 $(.field(stringify!($name), &$me.$name()))+
120 .finish()
121 }
122}
123
124macro_rules! delegate_flag {
125 ($item:ident, {$($name:ident),+}) => {
126 $(pub fn $name(&self) -> bool {
127 self.$item.map(|i| i.$name()).unwrap_or(false)
128 })+
129 }
130}
131
132macro_rules! master_attr_reader {
133 ($name:ident, $kind:ty) => {
134 pub fn $name(&self) -> Option<&$kind> {
135 self.$name.as_ref()
136 }
137 }
138}
139
140#[derive(Copy, Clone)]
141pub struct VersionInformation {
142 eax: u32,
143 ebx: u32,
144 ecx: u32,
145 edx: u32,
146}
147
148impl VersionInformation {
149 fn new() -> VersionInformation {
150 let (a, b, c, d) = cpuid(RequestType::VersionInformation);
151 VersionInformation { eax: a, ebx: b, ecx: c, edx: d }
152 }
153
154 pub fn family_id(self) -> u32 {
155 let family_id = bits_of(self.eax, 8, 11);
156 let extended_family_id = bits_of(self.eax, 20, 27);
157
158 if family_id != 0x0F {
159 family_id
160 } else {
161 extended_family_id + family_id
162 }
163 }
164
165 pub fn model_id(self) -> u32 {
166 let family_id = self.family_id();
167 let model_id = bits_of(self.eax, 4, 7);
168 let extended_model_id = bits_of(self.eax, 16, 19);
169
170 if family_id == 0x06 || family_id == 0x0F {
171 (extended_model_id << 4) + model_id
172 } else {
173 model_id
174 }
175 }
176
177 pub fn stepping(self) -> u32 {
178 bits_of(self.eax, 0, 3)
179 }
180
181 fn processor_signature(self) -> u32 {
182 self.eax
183 }
184
185 pub fn max_logical_processor_ids(self) -> Option<u8> {
190 if self.htt() {
191 Some((self.ebx >> 16) as u8)
192 } else {
193 None
194 }
195 }
196
197 pub fn local_logical_processor_id(self) -> u8 {
207 (self.ebx >> 24) as u8
208 }
209
210 pub fn brand_string(self) -> Option<&'static str> {
211 let brand_index = bits_of(self.ebx, 0, 7);
212 let processor_signature = self.processor_signature();
213
214 match brand_index {
215 0x00 => None,
216 0x01 => Some("Intel(R) Celeron(R)"),
217 0x02 => Some("Intel(R) Pentium(R) III"),
218 0x03 => {
219 if processor_signature == 0x06B1 {
220 Some("Intel(R) Celeron(R)")
221 } else {
222 Some("Intel(R) Pentium(R) III Xeon(R)")
223 }
224 },
225 0x04 => Some("Intel(R) Pentium(R) III"),
226 0x06 => Some("Mobile Intel(R) Pentium(R) III-M"),
227 0x07 => Some("Mobile Intel(R) Celeron(R)"),
228 0x08 => Some("Intel(R) Pentium(R) 4"),
229 0x09 => Some("Intel(R) Pentium(R) 4"),
230 0x0A => Some("Intel(R) Celeron(R)"),
231 0x0B => {
232 if processor_signature == 0x0F13 {
233 Some("Intel(R) Xeon(R) MP")
234 } else {
235 Some("Intel(R) Xeon(R)")
236 }
237 },
238 0x0C => Some("Intel(R) Xeon(R) MP"),
239 0x0E => {
240 if processor_signature == 0x0F13 {
241 Some("Intel(R) Xeon(R)")
242 } else {
243 Some("Mobile Intel(R) Pentium(R) 4-M")
244 }
245 },
246 0x0F => Some("Mobile Intel(R) Celeron(R)"),
247 0x11 => Some("Mobile Genuine Intel(R)"),
248 0x12 => Some("Intel(R) Celeron(R) M"),
249 0x13 => Some("Mobile Intel(R) Celeron(R)"),
250 0x14 => Some("Intel(R) Celeron(R)"),
251 0x15 => Some("Mobile Genuine Intel(R)"),
252 0x16 => Some("Intel(R) Pentium(R) M"),
253 0x17 => Some("Mobile Intel(R) Celeron(R)"),
254 _ => None,
255 }
256 }
257
258 bit!(ecx, {
259 0 => sse3,
260 1 => pclmulqdq,
261 2 => dtes64,
262 3 => monitor,
263 4 => ds_cpl,
264 5 => vmx,
265 6 => smx,
266 7 => eist,
267 8 => tm2,
268 9 => ssse3,
269 10 => cnxt_id,
270 11 => sdbg,
271 12 => fma,
272 13 => cmpxchg16b,
273 14 => xtpr_update_control,
274 15 => pdcm,
275 17 => pcid,
277 18 => dca,
278 19 => sse4_1,
279 20 => sse4_2,
280 21 => x2apic,
281 22 => movbe,
282 23 => popcnt,
283 24 => tsc_deadline,
284 25 => aesni,
285 26 => xsave,
286 27 => osxsave,
287 28 => avx,
288 29 => f16c,
289 30 => rdrand
290 });
292
293 bit!(edx, {
294 0 => fpu,
295 1 => vme,
296 2 => de,
297 3 => pse,
298 4 => tsc,
299 5 => msr,
300 6 => pae,
301 7 => mce,
302 8 => cx8,
303 9 => apic,
304 11 => sep,
306 12 => mtrr,
307 13 => pge,
308 14 => mca,
309 15 => cmov,
310 16 => pat,
311 17 => pse_36,
312 18 => psn,
313 19 => clfsh,
314 21 => ds,
316 22 => acpi,
317 23 => mmx,
318 24 => fxsr,
319 25 => sse,
320 26 => sse2,
321 27 => ss,
322 28 => htt,
323 29 => tm,
324 31 => pbe
326 });
327}
328
329impl fmt::Debug for VersionInformation {
330 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
331 dump!(self, f, "VersionInformation", {
332 family_id,
333 model_id,
334 stepping,
335 max_logical_processor_ids,
336 local_logical_processor_id,
337 brand_string,
338 sse3,
339 pclmulqdq,
340 dtes64,
341 monitor,
342 ds_cpl,
343 vmx,
344 smx,
345 eist,
346 tm2,
347 ssse3,
348 cnxt_id,
349 sdbg,
350 fma,
351 cmpxchg16b,
352 xtpr_update_control,
353 pdcm,
354 pcid,
355 dca,
356 sse4_1,
357 sse4_2,
358 x2apic,
359 movbe,
360 popcnt,
361 tsc_deadline,
362 aesni,
363 xsave,
364 osxsave,
365 avx,
366 f16c,
367 rdrand,
368 fpu,
369 vme,
370 de,
371 pse,
372 tsc,
373 msr,
374 pae,
375 mce,
376 cx8,
377 apic,
378 sep,
379 mtrr,
380 pge,
381 mca,
382 cmov,
383 pat,
384 pse_36,
385 psn,
386 clfsh,
387 ds,
388 acpi,
389 mmx,
390 fxsr,
391 sse,
392 sse2,
393 ss,
394 htt,
395 tm,
396 pbe
397 })
398 }
399}
400
401#[derive(Copy,Clone)]
402pub struct ExtendedProcessorSignature {
403 ecx: u32,
404 edx: u32,
405}
406
407impl ExtendedProcessorSignature {
408 fn new() -> ExtendedProcessorSignature {
409 let (_, _, c, d) = cpuid(RequestType::ExtendedProcessorSignature);
410 ExtendedProcessorSignature { ecx: c, edx: d }
411 }
412
413 bit!(ecx, {
414 0 => lahf_sahf_in_64_bit,
415 5 => lzcnt, 6 => sse4a, 8 => prefetchw,
420 21 => tbm });
424
425 bit!(edx, {
426 11 => syscall_sysret_in_64_bit,
428 20 => execute_disable,
430 26 => gigabyte_pages,
432 27 => rdtscp_and_ia32_tsc_aux,
433 29 => intel_64_bit_architecture
435 });
437}
438
439impl fmt::Debug for ExtendedProcessorSignature {
440 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
441 dump!(self, f, "ExtendedProcessorSignature", {
442 lahf_sahf_in_64_bit,
443 lzcnt,
444 prefetchw,
445 tbm,
446 sse4a,
447 syscall_sysret_in_64_bit,
448 execute_disable,
449 gigabyte_pages,
450 rdtscp_and_ia32_tsc_aux,
451 intel_64_bit_architecture
452 })
453 }
454}
455
456const BRAND_STRING_LENGTH: usize = 3 * 4 * 4;
458
459pub struct BrandString {
460 bytes: [u8; BRAND_STRING_LENGTH],
461}
462
463impl BrandString {
464 fn new() -> BrandString {
465 fn append_bytes(a: RequestType, bytes: &mut [u8]) {
466 let (a, b, c, d) = cpuid(a);
467
468 let result_bytes =
469 as_bytes(&a).iter()
470 .chain(as_bytes(&b).iter())
471 .chain(as_bytes(&c).iter())
472 .chain(as_bytes(&d).iter());
473
474 for (output, input) in bytes.iter_mut().zip(result_bytes) {
475 *output = *input
476 }
477 }
478
479 let mut brand_string = BrandString { bytes: [0; BRAND_STRING_LENGTH] };
480 append_bytes(RequestType::BrandString1, &mut brand_string.bytes[0..]);
481 append_bytes(RequestType::BrandString2, &mut brand_string.bytes[16..]);
482 append_bytes(RequestType::BrandString3, &mut brand_string.bytes[32..]);
483 brand_string
484 }
485}
486
487impl Clone for BrandString {
488 fn clone(&self) -> Self {
489 let mut bytes = [0; BRAND_STRING_LENGTH];
490 for (d, s) in bytes.iter_mut().zip(self.bytes.iter()) {
491 *d = *s;
492 }
493 BrandString { bytes: bytes }
494 }
495}
496
497impl Deref for BrandString {
498 type Target = str;
499
500 fn deref(&self) -> &str {
501 let nul_terminator = self.bytes.iter().position(|&b| b == 0).unwrap_or(0);
502 let usable_bytes = &self.bytes[..nul_terminator];
503 unsafe { str::from_utf8_unchecked(usable_bytes) }.trim()
504 }
505}
506
507impl fmt::Display for BrandString {
508 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
509 (self as &str).fmt(f)
510 }
511}
512
513impl fmt::Debug for BrandString {
514 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
515 (self as &str).fmt(f)
516 }
517}
518
519#[derive(Copy,Clone)]
520pub struct ThermalPowerManagementInformation {
521 eax: u32,
522 ebx: u32,
523 ecx: u32,
524}
525
526impl ThermalPowerManagementInformation {
527 fn new() -> ThermalPowerManagementInformation {
528 let (a, b, c, _) = cpuid(RequestType::ThermalPowerManagementInformation);
529 ThermalPowerManagementInformation { eax: a, ebx: b, ecx: c }
530 }
531
532 bit!(eax, {
533 0 => digital_temperature_sensor,
534 1 => intel_turbo_boost,
535 2 => arat,
536 4 => pln,
538 5 => ecmd,
539 6 => ptm,
540 7 => hwp,
541 8 => hwp_notification,
542 9 => hwp_activity_window,
543 10 => hwp_energy_performance_preference,
544 13 => hdc
546 });
547
548 pub fn number_of_interrupt_thresholds(self) -> u32 {
549 bits_of(self.ebx, 0, 3)
550 }
551
552 bit!(ecx, {
553 0 => hardware_coordination_feedback,
554 3 => performance_energy_bias
556 });
557}
558
559impl fmt::Debug for ThermalPowerManagementInformation {
560 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
561 dump!(self, f, "ThermalPowerManagementInformation", {
562 digital_temperature_sensor,
563 intel_turbo_boost,
564 arat,
565 pln,
566 ecmd,
567 ptm,
568 hwp,
569 hwp_notification,
570 hwp_activity_window,
571 hwp_energy_performance_preference,
572 hdc,
573
574 number_of_interrupt_thresholds,
575
576 hardware_coordination_feedback,
577 performance_energy_bias
578 })
579 }
580}
581
582#[derive(Copy,Clone)]
583pub struct StructuredExtendedInformation {
584 ebx: u32,
585 ecx: u32,
586 edx: u32,
587}
588
589impl StructuredExtendedInformation {
590 fn new() -> StructuredExtendedInformation {
591 let (_, b, c, d) = cpuid(RequestType::StructuredExtendedInformation);
592 StructuredExtendedInformation { ebx: b, ecx: c, edx: d }
593 }
594
595 bit!(ebx, {
596 0 => fsgsbase,
597 1 => ia32_tsc_adjust_msr,
598 3 => bmi1,
600 4 => hle,
601 5 => avx2,
602 7 => smep,
604 8 => bmi2,
605 9 => enhanced_rep_movsb_stosb,
606 10 => invpcid,
607 11 => rtm,
608 12 => pqm,
609 13 => deprecates_fpu_cs_ds,
610 15 => pqe,
612 16 => avx512f,
613 17 => avx512dq,
614 18 => rdseed,
615 19 => adx,
616 20 => smap,
617 21 => avx512_ifma,
618 23 => clflushopt,
620 24 => clwb,
621 25 => intel_processor_trace,
622 26 => avx512pf,
623 27 => avx512er,
624 28 => avx512cd,
625 29 => sha,
626 30 => avx512bw,
627 31 => avx512vl
628 });
629
630 bit!(ecx, {
631 0 => prefetchwt1,
632 1 => avx512_vbmi,
633 2 => umip,
634 3 => pku,
635 4 => ospke,
636 6 => avx512_vbmi2,
638 8 => gfni,
640 9 => vaes,
641 10 => vpclmulqdq,
642 11 => avx512_vnni,
643 12 => avx512_bitalg,
644 14 => avx512_vpopcntdq,
646 30 => sgx
650 });
652
653 bit!(edx, {
654 2 => avx512_4vnniw,
656 3 => avx512_4fmaps
657 });
659}
660
661impl fmt::Debug for StructuredExtendedInformation {
662 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
663 dump!(self, f, "StructuredExtendedInformation", {
664 fsgsbase,
665 ia32_tsc_adjust_msr,
666 bmi1,
667 hle,
668 avx2,
669 smep,
670 bmi2,
671 enhanced_rep_movsb_stosb,
672 invpcid,
673 rtm,
674 pqm,
675 deprecates_fpu_cs_ds,
676 pqe,
677 avx512f,
678 avx512dq,
679 rdseed,
680 adx,
681 smap,
682 avx512_ifma,
683 clflushopt,
684 clwb,
685 intel_processor_trace,
686 avx512pf,
687 avx512er,
688 avx512cd,
689 sha,
690 avx512bw,
691 avx512vl,
692 prefetchwt1,
693 avx512_vbmi,
694 umip,
695 pku,
696 ospke,
697 avx512_vbmi2,
698 gfni,
699 vaes,
700 vpclmulqdq,
701 avx512_vnni,
702 avx512_bitalg,
703 avx512_vpopcntdq,
704 sgx,
705 avx512_4vnniw,
706 avx512_4fmaps
707 })
708 }
709}
710
711#[derive(Clone, Default)]
712pub struct ExtendedTopologyEnumeration {
713 level: u32,
714}
715
716impl ExtendedTopologyEnumeration {
717 pub fn new() -> ExtendedTopologyEnumeration {
718 ExtendedTopologyEnumeration::default()
719 }
720}
721
722impl Iterator for ExtendedTopologyEnumeration {
723 type Item = ExtendedTopologyLeaf;
724
725 fn next(&mut self) -> Option<Self::Item> {
726 let leaf = ExtendedTopologyLeaf::new(self.level);
727
728 self.level += 1;
729
730 leaf
731 }
732}
733
734impl fmt::Debug for ExtendedTopologyEnumeration {
735 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
736 f.debug_list().entries(self.clone()).finish()
737 }
738}
739
740#[repr(u8)]
741#[derive(Copy, Clone, Debug, PartialEq)]
742pub enum TopologyType {
743 Invalid = 0,
744 SMT = 1,
745 Core = 2,
746}
747
748#[derive(Copy, Clone)]
749pub struct ExtendedTopologyLeaf {
750 eax: u32,
751 ebx: u32,
752 ecx: u32,
753 edx: u32,
754}
755
756impl ExtendedTopologyLeaf {
757 fn new(level: u32) -> Option<ExtendedTopologyLeaf> {
758 let (eax, ebx, ecx, edx) = cpuid_ext(RequestType::ExtendedTopologyEnumeration, level);
759
760 if bits_of(ebx, 0, 15) != 0 {
762 Some(ExtendedTopologyLeaf { eax, ebx, ecx, edx })
763 } else {
764 None
765 }
766 }
767
768 fn shift_right_for_next_apic_id(&self) -> u32 {
776 bits_of(self.eax, 0, 4)
777 }
778
779 pub fn next_level_apic_id(&self) -> u32 {
781 self.current_logical_processor_id() >> self.shift_right_for_next_apic_id()
782 }
783
784 pub fn logical_processor_count(&self) -> u32 {
796 bits_of(self.ebx, 0, 15)
797 }
798
799 pub fn level_number(&self) -> u8 {
801 self.ecx as u8
802 }
803
804 pub fn level_type(&self) -> TopologyType {
806 match self.ecx >> 8 {
807 0 => TopologyType::Invalid,
808 1 => TopologyType::SMT,
809 2 => TopologyType::Core,
810 _ => unreachable!()
811 }
812 }
813
814 pub fn current_logical_processor_id(&self) -> u32 {
822 self.edx
823 }
824}
825
826impl fmt::Debug for ExtendedTopologyLeaf {
827 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
828 dump!(self, f, "ExtendedTopologyLeaf", {
829 level_number,
830 level_type,
831 logical_processor_count,
832 current_logical_processor_id,
833 next_level_apic_id
834 })
835 }
836}
837
838#[derive(Copy,Clone)]
839pub struct ProcessorExtendedState {
840 eax: u32,
841 ebx: u32,
842 ecx: u32,
843}
844
845impl ProcessorExtendedState {
846 fn new() -> ProcessorExtendedState {
847 let (a, b, c, _) = cpuid(RequestType::ProcessorExtendedState);
848 ProcessorExtendedState { eax: a, ebx: b, ecx: c }
849 }
850
851 bit!(eax, {
852 0 => x87_state,
853 1 => sse_state,
854 2 => avx_state,
855 8 => ia32_xss,
858 9 => pkru_state
859 });
861
862 pub fn mpx_state(self) -> u32 {
863 bits_of(self.eax, 3, 4)
864 }
865
866 pub fn avx_512_state(self) -> u32 {
867 bits_of(self.eax, 5, 7)
868 }
869
870 pub fn maximum_bytes_for_enabled_features(self) -> u32 {
871 self.ebx
872 }
873
874 pub fn maximum_bytes_for_supported_features(self) -> u32 {
875 self.ecx
876 }
877}
878
879impl fmt::Debug for ProcessorExtendedState {
880 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
881 dump!(self, f, "ProcessorExtendedState", {
882 x87_state,
883 sse_state,
884 avx_state,
885 mpx_state,
886 avx_512_state,
887 ia32_xss,
888 pkru_state,
889
890 maximum_bytes_for_enabled_features,
891
892 maximum_bytes_for_supported_features
893 })
894 }
895}
896
897#[derive(Copy,Clone)]
898pub struct ProcessorExtendedStateSecondary {
899 eax: u32,
900 ebx: u32,
901 ecx: u32,
902}
903
904impl ProcessorExtendedStateSecondary {
905 fn new() -> ProcessorExtendedStateSecondary {
906 let (a, b, c, _) = cpuid_ext(RequestType::ProcessorExtendedState, 0x00000001);
907 ProcessorExtendedStateSecondary { eax: a, ebx: b, ecx: c }
908 }
909
910 bit!(eax, {
911 0 => xsaveopt,
912 1 => xsavec_and_xrstor,
913 2 => xgetbv_with_ecx_1,
914 3 => xsaves_xrstors_and_ia32_xss
915 });
917
918 bit!(ecx, {
919 8 => pt_state
921 });
924
925 pub fn bytes_of_xsave_area_containing_all_states_enabled(self) -> u32 {
926 self.ebx
927 }
928}
929
930impl fmt::Debug for ProcessorExtendedStateSecondary {
931 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
932 dump!(self, f, "ProcessorExtendedStateSecondary", {
933 xsaveopt,
934 xsavec_and_xrstor,
935 xgetbv_with_ecx_1,
936 xsaves_xrstors_and_ia32_xss,
937
938 bytes_of_xsave_area_containing_all_states_enabled,
939
940 pt_state
941 })
942 }
943}
944
945#[derive(Debug, Copy, Clone)]
946pub enum CacheLineAssociativity {
947 Disabled,
948 DirectMapped,
949 TwoWay,
950 FourWay,
951 EightWay,
952 SixteenWay,
953 Full,
954}
955
956#[derive(Copy, Clone)]
957pub struct CacheLine(u32);
958
959impl CacheLine {
960 fn new() -> CacheLine {
961 let (_, _, c, _) = cpuid(RequestType::CacheLine);
962 CacheLine(c)
963 }
964
965 pub fn cache_line_size(self) -> u32 {
966 bits_of(self.0, 0, 7)
967 }
968
969 pub fn l2_associativity(self) -> Option<CacheLineAssociativity> {
970 match bits_of(self.0, 12, 15) {
971 0x00 => Some(CacheLineAssociativity::Disabled),
972 0x01 => Some(CacheLineAssociativity::DirectMapped),
973 0x02 => Some(CacheLineAssociativity::TwoWay),
974 0x04 => Some(CacheLineAssociativity::FourWay),
975 0x06 => Some(CacheLineAssociativity::EightWay),
976 0x08 => Some(CacheLineAssociativity::SixteenWay),
977 0x0F => Some(CacheLineAssociativity::Full),
978 _ => None,
979 }
980 }
981
982 pub fn cache_size(self) -> u32 {
983 bits_of(self.0, 16, 31)
984 }
985}
986
987impl fmt::Debug for CacheLine {
988 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
989 dump!(self, f, "CacheLine", {
990 cache_line_size,
991 l2_associativity,
992 cache_size
993 })
994 }
995}
996
997#[derive(Copy, Clone)]
998pub struct TimeStampCounter {
999 edx: u32,
1000}
1001
1002impl TimeStampCounter {
1003 fn new() -> TimeStampCounter {
1004 let (_, _, _, d) = cpuid(RequestType::TimeStampCounter);
1005 TimeStampCounter { edx: d }
1006 }
1007
1008 bit!(edx, {
1009 8 => invariant_tsc
1011 });
1013}
1014
1015impl fmt::Debug for TimeStampCounter {
1016 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1017 dump!(self, f, "TimeStampCounter", {
1018 invariant_tsc
1019 })
1020 }
1021}
1022
1023#[derive(Copy,Clone)]
1024pub struct PhysicalAddressSize(u32);
1025
1026impl PhysicalAddressSize {
1027 fn new() -> PhysicalAddressSize {
1028 let (a, _, _, _) = cpuid(RequestType::PhysicalAddressSize);
1029 PhysicalAddressSize(a)
1030 }
1031
1032 pub fn physical_address_bits(self) -> u32 {
1033 bits_of(self.0, 0, 7)
1034 }
1035
1036 pub fn linear_address_bits(self) -> u32 {
1037 bits_of(self.0, 8, 15)
1038 }
1039}
1040
1041impl fmt::Debug for PhysicalAddressSize {
1042 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1043 dump!(self, f, "PhysicalAddressSize", {
1044 physical_address_bits,
1045 linear_address_bits
1046 })
1047 }
1048}
1049
1050#[derive(Debug,Clone)]
1060pub struct Master {
1061 version_information: Option<VersionInformation>,
1063 thermal_power_management_information: Option<ThermalPowerManagementInformation>,
1064 structured_extended_information: Option<StructuredExtendedInformation>,
1065 extended_topology_enumeration: Option<ExtendedTopologyEnumeration>,
1066 processor_extended_state: Option<ProcessorExtendedState>,
1067 processor_extended_state_secondary: Option<ProcessorExtendedStateSecondary>,
1068 extended_processor_signature: Option<ExtendedProcessorSignature>,
1069 brand_string: Option<BrandString>,
1070 cache_line: Option<CacheLine>,
1071 time_stamp_counter: Option<TimeStampCounter>,
1072 physical_address_size: Option<PhysicalAddressSize>,
1073}
1074
1075impl Master {
1076 fn new() -> Master {
1077 fn when_supported<F, T>(max: u32, kind: RequestType, then: F) -> Option<T>
1078 where F: FnOnce() -> T
1079 {
1080 if max >= kind as u32 {
1081 Some(then())
1082 } else {
1083 None
1084 }
1085 }
1086
1087 let (max_value, _, _, _) = cpuid(RequestType::BasicInformation);
1088
1089 let vi = when_supported(max_value, RequestType::VersionInformation, || {
1090 VersionInformation::new()
1091 });
1092 let tpm = when_supported(max_value, RequestType::ThermalPowerManagementInformation, || {
1093 ThermalPowerManagementInformation::new()
1094 });
1095 let sei = when_supported(max_value, RequestType::StructuredExtendedInformation, || {
1096 StructuredExtendedInformation::new()
1097 });
1098 let ete = when_supported(max_value, RequestType::ExtendedTopologyEnumeration, || {
1099 ExtendedTopologyEnumeration::new()
1100 });
1101 let pes = when_supported(max_value, RequestType::ProcessorExtendedState, || {
1102 ProcessorExtendedState::new()
1103 });
1104 let pes_2 = when_supported(max_value, RequestType::ProcessorExtendedState, || {
1105 ProcessorExtendedStateSecondary::new()
1106 });
1107
1108 let (max_value, _, _, _) = cpuid(RequestType::ExtendedFunctionInformation);
1111
1112 let eps = when_supported(max_value, RequestType::ExtendedProcessorSignature, || {
1113 ExtendedProcessorSignature::new()
1114 });
1115 let brand_string = when_supported(max_value, RequestType::BrandString3, || {
1116 BrandString::new()
1117 });
1118 let cache_line = when_supported(max_value, RequestType::CacheLine, || {
1119 CacheLine::new()
1120 });
1121 let tsc = when_supported(max_value, RequestType::TimeStampCounter, || {
1122 TimeStampCounter::new()
1123 });
1124 let pas = when_supported(max_value, RequestType::PhysicalAddressSize, || {
1125 PhysicalAddressSize::new()
1126 });
1127
1128 Master {
1129 version_information: vi,
1130 thermal_power_management_information: tpm,
1131 structured_extended_information: sei,
1132 extended_topology_enumeration: ete,
1133 processor_extended_state: pes,
1134 processor_extended_state_secondary: pes_2,
1135 extended_processor_signature: eps,
1136 brand_string: brand_string,
1137 cache_line: cache_line,
1138 time_stamp_counter: tsc,
1139 physical_address_size: pas,
1140 }
1141 }
1142
1143 master_attr_reader!(version_information, VersionInformation);
1144 master_attr_reader!(thermal_power_management_information, ThermalPowerManagementInformation);
1145 master_attr_reader!(structured_extended_information, StructuredExtendedInformation);
1146 master_attr_reader!(extended_topology_enumeration, ExtendedTopologyEnumeration);
1147 master_attr_reader!(processor_extended_state, ProcessorExtendedState);
1148 master_attr_reader!(processor_extended_state_secondary, ProcessorExtendedStateSecondary);
1149 master_attr_reader!(extended_processor_signature, ExtendedProcessorSignature);
1150 master_attr_reader!(cache_line, CacheLine);
1151 master_attr_reader!(time_stamp_counter, TimeStampCounter);
1152 master_attr_reader!(physical_address_size, PhysicalAddressSize);
1153
1154 pub fn brand_string(&self) -> Option<&str> {
1155 self.brand_string.as_ref().map(|bs| bs as &str).or({
1156 self.version_information.and_then(|vi| vi.brand_string())
1157 })
1158 }
1159
1160 delegate_flag!(version_information, {
1161 sse3,
1162 pclmulqdq,
1163 dtes64,
1164 monitor,
1165 ds_cpl,
1166 vmx,
1167 smx,
1168 eist,
1169 tm2,
1170 ssse3,
1171 cnxt_id,
1172 sdbg,
1173 fma,
1174 cmpxchg16b,
1175 xtpr_update_control,
1176 pdcm,
1177 pcid,
1178 dca,
1179 sse4_1,
1180 sse4_2,
1181 x2apic,
1182 movbe,
1183 popcnt,
1184 tsc_deadline,
1185 aesni,
1186 xsave,
1187 osxsave,
1188 avx,
1189 f16c,
1190 rdrand,
1191 fpu,
1192 vme,
1193 de,
1194 pse,
1195 tsc,
1196 msr,
1197 pae,
1198 mce,
1199 cx8,
1200 apic,
1201 sep,
1202 mtrr,
1203 pge,
1204 mca,
1205 cmov,
1206 pat,
1207 pse_36,
1208 psn,
1209 clfsh,
1210 ds,
1211 acpi,
1212 mmx,
1213 fxsr,
1214 sse,
1215 sse2,
1216 ss,
1217 htt,
1218 tm,
1219 pbe
1220 });
1221
1222 delegate_flag!(thermal_power_management_information, {
1223 digital_temperature_sensor,
1224 intel_turbo_boost,
1225 arat,
1226 pln,
1227 ecmd,
1228 ptm,
1229 hwp,
1230 hwp_notification,
1231 hwp_activity_window,
1232 hwp_energy_performance_preference,
1233 hdc,
1234 hardware_coordination_feedback,
1235 performance_energy_bias
1236 });
1237
1238 delegate_flag!(structured_extended_information, {
1239 fsgsbase,
1240 ia32_tsc_adjust_msr,
1241 bmi1,
1242 hle,
1243 avx2,
1244 smep,
1245 bmi2,
1246 enhanced_rep_movsb_stosb,
1247 invpcid,
1248 rtm,
1249 pqm,
1250 deprecates_fpu_cs_ds,
1251 pqe,
1252 avx512f,
1253 avx512dq,
1254 rdseed,
1255 adx,
1256 smap,
1257 avx512_ifma,
1258 clflushopt,
1259 clwb,
1260 intel_processor_trace,
1261 avx512pf,
1262 avx512er,
1263 avx512cd,
1264 sha,
1265 avx512bw,
1266 avx512vl,
1267 prefetchwt1,
1268 avx512_vbmi,
1269 umip,
1270 pku,
1271 ospke,
1272 avx512_vbmi2,
1273 gfni,
1274 vaes,
1275 vpclmulqdq,
1276 avx512_vnni,
1277 avx512_bitalg,
1278 avx512_vpopcntdq,
1279 sgx,
1280 avx512_4vnniw,
1281 avx512_4fmaps
1282 });
1283
1284 delegate_flag!(processor_extended_state, {
1285 x87_state,
1286 sse_state,
1287 avx_state,
1288 ia32_xss,
1289 pkru_state
1290 });
1291
1292 delegate_flag!(processor_extended_state_secondary, {
1293 xsaveopt,
1294 xsavec_and_xrstor,
1295 xgetbv_with_ecx_1,
1296 xsaves_xrstors_and_ia32_xss
1297 });
1298
1299 delegate_flag!(extended_processor_signature, {
1300 lahf_sahf_in_64_bit,
1301 lzcnt,
1302 prefetchw,
1303 tbm,
1304 sse4a,
1305 syscall_sysret_in_64_bit,
1306 execute_disable,
1307 gigabyte_pages,
1308 rdtscp_and_ia32_tsc_aux,
1309 intel_64_bit_architecture
1310 });
1311
1312 delegate_flag!(time_stamp_counter, {
1313 invariant_tsc
1314 });
1315}
1316
1317#[cfg(all(test, cpuid_available))]
1318mod test {
1319 use super::*;
1320
1321 #[test]
1322 fn brand_string_contains_intel_or_amd() {
1323 let master = master().unwrap();
1324 let brand_string = master.brand_string().unwrap();
1325
1326 let is_intel = brand_string.starts_with("Intel(R)");
1328 let is_amd = brand_string.starts_with("AMD");
1331
1332 assert!(is_intel || is_amd, "Brand string was {}", brand_string);
1333 }
1334}
1335
1336#[cfg(all(test, not(cpuid_available)))]
1337mod test {
1338 use super::*;
1339
1340 #[test]
1341 fn is_not_available() {
1342 assert!(master().is_none());
1343 }
1344}