dmidecode/structures/
007_cache.rs

1//! Cache Information (Type 7)
2//!
3//! Information in this structure defines the attributes of CPU cache device in the system. One
4//! structure is specified for each such device, whether the device is internal to or external to
5//! the CPU module. Cache modules can be associated with a processor structure in one or two ways
6//! depending on the SMBIOS version.
7
8use core::fmt;
9
10use bitflags::bitflags;
11
12use crate::{MalformedStructureError, RawStructure};
13
14/// The `Cache Information` table defined in the SMBIOS specification.
15///
16/// Optional fields will only be set if the version of the parsed SMBIOS table
17/// is high enough to have defined the field.
18#[derive(Clone, Debug, Eq, Hash, PartialEq)]
19pub struct Cache<'buffer> {
20    pub handle: u16,
21    /// String number for reference designation EXAMPLE: “CACHE1”, 0
22    pub socket_designation: &'buffer str,
23    /// Cache Configuration
24    pub cache_configuration: CacheConfiguration,
25    /// Maximum size that can be installed
26    pub maximum_cache_size: CacheSize,
27    /// Same format as Max Cache Size field; set to 0 if no cache is installed
28    pub installed_size: CacheSize,
29    /// Supported SRAM Type
30    pub supported_sram_type: CacheSramType,
31    /// Current SRAM Type
32    pub current_sram_type: CacheSramType,
33    /// Cache module speed, in nanoseconds. The value is 0 if the speed is unknown.
34    pub cache_speed: Option<u8>,
35    /// Error-correction scheme supported by this cache component
36    pub error_correction_type: Option<CacheErrorCorrectionType>,
37    /// Logical type of cache
38    pub system_cache_type: Option<SystemCacheType>,
39    /// Associativity of the cache
40    pub associativity: Option<CacheAssociativity>,
41    /// If this field is present, for cache sizes of 2047 MB or smaller the value in the Max size
42    /// in given granularity portion of the field equals the size given in the corresponding
43    /// portion of the Maximum Cache Size field, and the Granularity bit matches the value of the
44    /// Granularity bit in the Maximum Cache Size field.  For Cache sizes greater than 2047 MB, the
45    /// Maximum Cache Size field is set to 0xFFFF and the Maximum Cache Size 2 field is present,
46    /// the Granularity bit is set to 1b, and the size set as required;
47    pub maximum_cache_size_2: Option<CacheSize2>,
48    /// Same format as Maximum Cache Size 2 field; Absent or set to 0 if no cache is installed.
49    pub installed_size_2: Option<CacheSize2>,
50}
51
52#[derive(Clone, Debug, Eq, Hash, PartialEq)]
53pub struct CacheConfiguration {
54    /// Cache Level – 1 through 8
55    level: CacheLevel,
56    /// Cache Socketed (e.g. Cache on a Stick)
57    socketed: bool,
58    /// Location, relative to the CPU module
59    location: CacheLocation,
60    /// Enabled/Disabled (at boot time)
61    enabled_at_boot_time: bool,
62    /// Operational Mode
63    operational_mode: CacheOperationalMode,
64}
65
66#[derive(Clone, Debug, Eq, Hash, PartialEq)]
67pub enum CacheLevel {
68    L1,
69    L2,
70    L3,
71    L4,
72    L5,
73    L6,
74    L7,
75    L8,
76}
77
78#[derive(Clone, Debug, Eq, Hash, PartialEq)]
79pub enum CacheLocation {
80    Internal,
81    External,
82    Reserved,
83    Unknown,
84}
85
86#[derive(Clone, Debug, Eq, Hash, PartialEq)]
87pub enum CacheOperationalMode {
88    WriteThrough,
89    WriteBack,
90    ValuesWithMemoryAddress,
91    Unknown,
92}
93
94/// Cache size is same for Maximum Cache Size and Installed Size
95#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq)]
96pub enum CacheSize {
97    Granularity1K(u16),
98    Granularity64K(u16),
99}
100
101bitflags! {
102    /// Cache SRAM Type is same for Supported SRAM Type and Current SRAM Type
103    #[derive(Debug, Clone, PartialEq, Eq, Hash)]
104    pub struct CacheSramType: u16 {
105        const OTHER             = 0b0000_0001;
106        const UNKNOWN           = 0b0000_0010;
107        const NONBURST          = 0b0000_0100;
108        const BURST             = 0b0000_1000;
109        const PIPELINE_BURST    = 0b0001_0000;
110        const SYNCHRONOUS       = 0b0010_0000;
111        const ASYNCHRONOUS      = 0b0100_0000;
112    }
113}
114
115/// Error Correction Type field
116#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq)]
117pub enum CacheErrorCorrectionType {
118    Other,
119    Unknown,
120    None,
121    Parity,
122    SingleBitEcc,
123    MultiBitEcc,
124    Undefined(u8),
125}
126
127/// The cache type for a cache level (L1, L2, L3, ...) is type 03h (Instruction) when all the
128/// caches at that level are Instruction caches. The cache type for a specific cache level (L1, L2,
129/// L3, ...) is type 04h (Data) when all the caches at that level are Data caches. The cache type
130/// for a cache level (L1, L2, L3, ...) is type 05h (Unified) when the caches at that level are a
131/// mix of Instruction and Data caches.
132#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq)]
133pub enum SystemCacheType {
134    Other,
135    Unknown,
136    Instruction,
137    Data,
138    Unified,
139    Undefined(u8),
140}
141
142/// Associativity field
143#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq)]
144pub enum CacheAssociativity {
145    Other,
146    Unknown,
147    DirectMapped,
148    TwowaySetAssociative,
149    FourWaySetAssociative,
150    FullyAssociative,
151    EightWaySetAssociative,
152    SixteenWaySetAssociative,
153    TwelveWaySetAssociative,
154    TwentyFourWaySetAssociative,
155    ThirtyTwoWaySetAssociative,
156    FourtyEightWaySetAssociative,
157    SixtyFourWaySetAssociative,
158    TwentyWaySetAssociative,
159    Undefined(u8),
160}
161
162/// Cache size is same for Maximum Cache Size and Installed Size
163#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq)]
164pub enum CacheSize2 {
165    Granularity1K(u32),
166    Granularity64K(u32),
167}
168
169impl<'buffer> Cache<'buffer> {
170    pub(crate) fn try_from(structure: RawStructure<'buffer>) -> Result<Cache<'buffer>, MalformedStructureError> {
171        #[repr(C)]
172        #[repr(packed)]
173        struct CachePacked3_1 {
174            socket_designation: u8,
175            cache_configuration: u16,
176            maximum_cache_size: u16,
177            installed_size: u16,
178            supported_sram_type: u16,
179            current_sram_type: u16,
180            cache_speed: u8,
181            error_correction_type: u8,
182            system_cache_type: u8,
183            associativity: u8,
184            maximum_cache_size_2: u32,
185            installed_size_2: u32,
186        }
187
188        #[repr(C)]
189        #[repr(packed)]
190        struct CachePacked2_1 {
191            socket_designation: u8,
192            cache_configuration: u16,
193            maximum_cache_size: u16,
194            installed_size: u16,
195            supported_sram_type: u16,
196            current_sram_type: u16,
197            cache_speed: u8,
198            error_correction_type: u8,
199            system_cache_type: u8,
200            associativity: u8,
201        }
202
203        #[repr(C)]
204        #[repr(packed)]
205        struct CachePacked2_0 {
206            socket_designation: u8,
207            cache_configuration: u16,
208            maximum_cache_size: u16,
209            installed_size: u16,
210            supported_sram_type: u16,
211            current_sram_type: u16,
212        }
213
214        match structure.version {
215            v if v > (3, 1).into() => {
216                let_as_struct!(packed, CachePacked3_1, structure.data);
217                Ok(Cache {
218                    handle: structure.handle,
219                    socket_designation: structure.find_string(packed.socket_designation)?,
220                    cache_configuration: packed.cache_configuration.into(),
221                    maximum_cache_size: packed.maximum_cache_size.into(),
222                    installed_size: packed.installed_size.into(),
223                    supported_sram_type: CacheSramType::from_bits_truncate(packed.supported_sram_type),
224                    current_sram_type: CacheSramType::from_bits_truncate(packed.current_sram_type),
225                    cache_speed: Some(packed.cache_speed),
226                    error_correction_type: Some(packed.error_correction_type.into()),
227                    system_cache_type: Some(packed.system_cache_type.into()),
228                    associativity: Some(packed.associativity.into()),
229                    maximum_cache_size_2: Some(packed.maximum_cache_size_2.into()),
230                    installed_size_2: Some(packed.installed_size_2.into()),
231                })
232            }
233            v if v > (2, 1).into() => {
234                let_as_struct!(packed, CachePacked2_1, structure.data);
235                Ok(Cache {
236                    handle: structure.handle,
237                    socket_designation: structure.find_string(packed.socket_designation)?,
238                    cache_configuration: packed.cache_configuration.into(),
239                    maximum_cache_size: packed.maximum_cache_size.into(),
240                    installed_size: packed.installed_size.into(),
241                    supported_sram_type: CacheSramType::from_bits_truncate(packed.supported_sram_type),
242                    current_sram_type: CacheSramType::from_bits_truncate(packed.current_sram_type),
243                    cache_speed: Some(packed.cache_speed),
244                    error_correction_type: Some(packed.error_correction_type.into()),
245                    system_cache_type: Some(packed.system_cache_type.into()),
246                    associativity: Some(packed.associativity.into()),
247                    maximum_cache_size_2: None,
248                    installed_size_2: None,
249                })
250            }
251            v if v > (2, 0).into() => {
252                let_as_struct!(packed, CachePacked2_0, structure.data);
253                Ok(Cache {
254                    handle: structure.handle,
255                    socket_designation: structure.find_string(packed.socket_designation)?,
256                    cache_configuration: packed.cache_configuration.into(),
257                    maximum_cache_size: packed.maximum_cache_size.into(),
258                    installed_size: packed.installed_size.into(),
259                    supported_sram_type: CacheSramType::from_bits_truncate(packed.supported_sram_type),
260                    current_sram_type: CacheSramType::from_bits_truncate(packed.current_sram_type),
261                    cache_speed: None,
262                    error_correction_type: None,
263                    system_cache_type: None,
264                    associativity: None,
265                    maximum_cache_size_2: None,
266                    installed_size_2: None,
267                })
268            }
269            _ => unreachable!(),
270        }
271    }
272}
273
274impl From<u16> for CacheConfiguration {
275    fn from(word: u16) -> CacheConfiguration {
276        CacheConfiguration {
277            level: CacheLevel::from(word & 0b0000_0111),
278            socketed: (word & 0b0000_1000) >> 3 == 1,
279            location: CacheLocation::from((word & 0b0110_0000) >> 5),
280            enabled_at_boot_time: (word & 0b1000_0000) >> 7 == 1,
281            operational_mode: CacheOperationalMode::from((word & 0b0000_0011_0000_0000) >> 8),
282        }
283    }
284}
285
286impl From<u16> for CacheSize {
287    fn from(word: u16) -> CacheSize {
288        let val = word & (!(1 << 15));
289        if word & (1 << 15) == 0 {
290            CacheSize::Granularity1K(val)
291        } else {
292            CacheSize::Granularity64K(val)
293        }
294    }
295}
296impl CacheSize {
297    pub fn bytes(&self) -> u64 {
298        match &self {
299            Self::Granularity1K(val) => (*val as u64) * (1 << 10),
300            Self::Granularity64K(val) => (*val as u64) * (1 << 16),
301        }
302    }
303}
304
305impl From<u16> for CacheLevel {
306    fn from(word: u16) -> CacheLevel {
307        match word {
308            0 => CacheLevel::L1,
309            1 => CacheLevel::L2,
310            2 => CacheLevel::L3,
311            3 => CacheLevel::L4,
312            4 => CacheLevel::L5,
313            5 => CacheLevel::L6,
314            6 => CacheLevel::L7,
315            7 => CacheLevel::L8,
316            _ => unreachable!(),
317        }
318    }
319}
320impl fmt::Display for CacheLevel {
321    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
322        match self {
323            Self::L1 => write!(f, "L1"),
324            Self::L2 => write!(f, "L2"),
325            Self::L3 => write!(f, "L3"),
326            Self::L4 => write!(f, "L4"),
327            Self::L5 => write!(f, "L5"),
328            Self::L6 => write!(f, "L6"),
329            Self::L7 => write!(f, "L7"),
330            Self::L8 => write!(f, "L8"),
331        }
332    }
333}
334
335impl From<u16> for CacheLocation {
336    fn from(word: u16) -> CacheLocation {
337        match word {
338            0 => CacheLocation::Internal,
339            1 => CacheLocation::External,
340            2 => CacheLocation::Reserved,
341            3 => CacheLocation::Unknown,
342            _ => unreachable!(),
343        }
344    }
345}
346impl fmt::Display for CacheLocation {
347    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
348        match self {
349            Self::Internal => write!(f, "Internal"),
350            Self::External => write!(f, "External"),
351            Self::Reserved => write!(f, "Reserved"),
352            Self::Unknown => write!(f, "Unknown"),
353        }
354    }
355}
356
357impl From<u16> for CacheOperationalMode {
358    fn from(word: u16) -> CacheOperationalMode {
359        match word {
360            0 => CacheOperationalMode::WriteThrough,
361            1 => CacheOperationalMode::WriteBack,
362            2 => CacheOperationalMode::ValuesWithMemoryAddress,
363            3 => CacheOperationalMode::Unknown,
364            _ => unreachable!(),
365        }
366    }
367}
368impl fmt::Display for CacheOperationalMode {
369    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
370        match self {
371            Self::WriteThrough => write!(f, "Write Through"),
372            Self::WriteBack => write!(f, "Write Back"),
373            Self::ValuesWithMemoryAddress => write!(f, "Values with Memory Address"),
374            Self::Unknown => write!(f, "Unknown"),
375        }
376    }
377}
378
379impl From<u8> for CacheErrorCorrectionType {
380    fn from(byte: u8) -> CacheErrorCorrectionType {
381        match byte {
382            0x01 => CacheErrorCorrectionType::Other,
383            0x02 => CacheErrorCorrectionType::Unknown,
384            0x03 => CacheErrorCorrectionType::None,
385            0x04 => CacheErrorCorrectionType::Parity,
386            0x05 => CacheErrorCorrectionType::SingleBitEcc,
387            0x06 => CacheErrorCorrectionType::MultiBitEcc,
388            t => CacheErrorCorrectionType::Undefined(t),
389        }
390    }
391}
392impl fmt::Display for CacheErrorCorrectionType {
393    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
394        match self {
395            Self::Other => write!(f, "Other"),
396            Self::Unknown => write!(f, "Unknown"),
397            Self::None => write!(f, "None"),
398            Self::Parity => write!(f, "Parity"),
399            Self::SingleBitEcc => write!(f, "Single-bit ECC"),
400            Self::MultiBitEcc => write!(f, "Multi-bit ECC"),
401            Self::Undefined(t) => write!(f, "Undefined: {}", t),
402        }
403    }
404}
405
406impl From<u8> for SystemCacheType {
407    fn from(byte: u8) -> SystemCacheType {
408        match byte {
409            0x01 => SystemCacheType::Other,
410            0x02 => SystemCacheType::Unknown,
411            0x03 => SystemCacheType::Instruction,
412            0x04 => SystemCacheType::Data,
413            0x05 => SystemCacheType::Unified,
414            t => SystemCacheType::Undefined(t),
415        }
416    }
417}
418impl fmt::Display for SystemCacheType {
419    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
420        match self {
421            Self::Other => write!(f, "Other"),
422            Self::Unknown => write!(f, "Unknown"),
423            Self::Instruction => write!(f, "Instruction"),
424            Self::Data => write!(f, "Data"),
425            Self::Unified => write!(f, "Unified"),
426            Self::Undefined(t) => write!(f, "Undefined: {}", t),
427        }
428    }
429}
430
431impl From<u8> for CacheAssociativity {
432    fn from(byte: u8) -> CacheAssociativity {
433        match byte {
434            0x01 => CacheAssociativity::Other,
435            0x02 => CacheAssociativity::Unknown,
436            0x03 => CacheAssociativity::DirectMapped,
437            0x04 => CacheAssociativity::TwowaySetAssociative,
438            0x05 => CacheAssociativity::FourWaySetAssociative,
439            0x06 => CacheAssociativity::FullyAssociative,
440            0x07 => CacheAssociativity::EightWaySetAssociative,
441            0x08 => CacheAssociativity::SixteenWaySetAssociative,
442            0x09 => CacheAssociativity::TwelveWaySetAssociative,
443            0x0A => CacheAssociativity::TwentyFourWaySetAssociative,
444            0x0B => CacheAssociativity::ThirtyTwoWaySetAssociative,
445            0x0C => CacheAssociativity::FourtyEightWaySetAssociative,
446            0x0D => CacheAssociativity::SixtyFourWaySetAssociative,
447            0x0E => CacheAssociativity::TwentyWaySetAssociative,
448            t => CacheAssociativity::Undefined(t),
449        }
450    }
451}
452impl fmt::Display for CacheAssociativity {
453    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
454        match self {
455            Self::Other => write!(f, "Other"),
456            Self::Unknown => write!(f, "Unknown"),
457            Self::DirectMapped => write!(f, "Direct Mapped"),
458            Self::TwowaySetAssociative => write!(f, "2-way Set-Associative"),
459            Self::FourWaySetAssociative => write!(f, "4-way Set-Associative"),
460            Self::FullyAssociative => write!(f, "Fully Associative"),
461            Self::EightWaySetAssociative => write!(f, "8-way Set-Associative"),
462            Self::SixteenWaySetAssociative => write!(f, "16-way Set-Associative"),
463            Self::TwelveWaySetAssociative => write!(f, "12-way Set-Associative"),
464            Self::TwentyFourWaySetAssociative => write!(f, "24-way Set-Associative"),
465            Self::ThirtyTwoWaySetAssociative => write!(f, "32-way Set-Associative"),
466            Self::FourtyEightWaySetAssociative => write!(f, "48-way Set-Associative"),
467            Self::SixtyFourWaySetAssociative => write!(f, "64-way Set-Associative"),
468            Self::TwentyWaySetAssociative => write!(f, "20-way Set-Associative"),
469            Self::Undefined(t) => write!(f, "Undefined: {}", t),
470        }
471    }
472}
473
474impl From<u32> for CacheSize2 {
475    fn from(dword: u32) -> CacheSize2 {
476        let val = dword & (!(1 << 31));
477        if dword & (1 << 31) == 0 {
478            CacheSize2::Granularity1K(val)
479        } else {
480            CacheSize2::Granularity64K(val)
481        }
482    }
483}
484impl CacheSize2 {
485    pub fn bytes(&self) -> u64 {
486        match &self {
487            Self::Granularity1K(val) => (*val as u64) * (1 << 10),
488            Self::Granularity64K(val) => (*val as u64) * (1 << 16),
489        }
490    }
491}
492
493#[cfg(test)]
494mod tests {
495    use super::*;
496    #[test]
497    fn cache_configuration() {
498        let data = 0b0000_0010_1010_1010;
499        let sample = CacheConfiguration {
500            level: CacheLevel::L3,
501            socketed: true,
502            location: CacheLocation::External,
503            enabled_at_boot_time: true,
504            operational_mode: CacheOperationalMode::ValuesWithMemoryAddress,
505        };
506        let result: CacheConfiguration = data.into();
507        assert_eq!(sample, result);
508    }
509    #[test]
510    fn cache_size() {
511        let data = [0b0000_0010_1010_1010, 0b1000_0010_1010_1010];
512        let cs_1k = CacheSize::from(data[0]);
513        let cs_64k = CacheSize::from(data[1]);
514        let cs2_1k = CacheSize2::from((data[0] as u32) << 16);
515        let cs2_64k = CacheSize2::from((data[1] as u32) << 16);
516        assert_eq!(CacheSize::Granularity1K(682), cs_1k);
517        assert_eq!(682 * 1024, cs_1k.bytes());
518        assert_eq!(CacheSize::Granularity64K(682), cs_64k);
519        assert_eq!(682 * 65536, cs_64k.bytes());
520        assert_eq!(CacheSize2::Granularity1K(44695552), cs2_1k);
521        assert_eq!(44695552 * 1024, cs2_1k.bytes());
522        assert_eq!(CacheSize2::Granularity64K(44695552), cs2_64k);
523        assert_eq!(44695552 * 65536, cs2_64k.bytes());
524    }
525    #[test]
526    fn cache_enums() {
527        let data = 0b0101_0101;
528        let sram = CacheSramType::from_bits_truncate(data);
529        assert!(sram.contains(CacheSramType::OTHER));
530        assert!(sram.contains(CacheSramType::NONBURST));
531        assert!(sram.contains(CacheSramType::PIPELINE_BURST));
532        assert!(sram.contains(CacheSramType::ASYNCHRONOUS));
533        assert_eq!(CacheErrorCorrectionType::Undefined(85), (data as u8).into());
534        assert_eq!(CacheErrorCorrectionType::SingleBitEcc, ((data & 0b111) as u8).into());
535        assert_eq!(SystemCacheType::Undefined(85), (data as u8).into());
536        assert_eq!(SystemCacheType::Unified, ((data & 0b111) as u8).into());
537        assert_eq!(CacheAssociativity::Undefined(85), (data as u8).into());
538        assert_eq!(
539            CacheAssociativity::FourWaySetAssociative,
540            ((data & 0b1111) as u8).into()
541        );
542    }
543}