1use core::fmt;
9
10use bitflags::bitflags;
11
12use crate::{MalformedStructureError, RawStructure};
13
14#[derive(Clone, Debug, Eq, Hash, PartialEq)]
19pub struct Cache<'buffer> {
20 pub handle: u16,
21 pub socket_designation: &'buffer str,
23 pub cache_configuration: CacheConfiguration,
25 pub maximum_cache_size: CacheSize,
27 pub installed_size: CacheSize,
29 pub supported_sram_type: CacheSramType,
31 pub current_sram_type: CacheSramType,
33 pub cache_speed: Option<u8>,
35 pub error_correction_type: Option<CacheErrorCorrectionType>,
37 pub system_cache_type: Option<SystemCacheType>,
39 pub associativity: Option<CacheAssociativity>,
41 pub maximum_cache_size_2: Option<CacheSize2>,
48 pub installed_size_2: Option<CacheSize2>,
50}
51
52#[derive(Clone, Debug, Eq, Hash, PartialEq)]
53pub struct CacheConfiguration {
54 level: CacheLevel,
56 socketed: bool,
58 location: CacheLocation,
60 enabled_at_boot_time: bool,
62 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#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq)]
96pub enum CacheSize {
97 Granularity1K(u16),
98 Granularity64K(u16),
99}
100
101bitflags! {
102 #[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#[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#[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#[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#[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}