1use crate::{SMBiosStruct, UndefinedStruct};
2use serde::{ser::SerializeSeq, ser::SerializeStruct, Serialize, Serializer};
3use std::fmt;
4use std::ops::Deref;
5
6pub struct SMBiosSystemEventLog<'a> {
17 parts: &'a UndefinedStruct,
18}
19
20impl<'a> SMBiosStruct<'a> for SMBiosSystemEventLog<'a> {
21 const STRUCT_TYPE: u8 = 15u8;
22
23 fn new(parts: &'a UndefinedStruct) -> Self {
24 Self { parts }
25 }
26
27 fn parts(&self) -> &'a UndefinedStruct {
28 self.parts
29 }
30}
31
32impl<'a> SMBiosSystemEventLog<'a> {
33 const LOG_TYPE_DESCRIPTORS_OFFSET: usize = 0x17usize;
34
35 pub fn log_area_length(&self) -> Option<u16> {
38 self.parts.get_field_word(0x04)
39 }
40
41 pub fn log_header_start_offset(&self) -> Option<u16> {
48 self.parts.get_field_word(0x06)
49 }
50
51 pub fn log_data_start_offset(&self) -> Option<u16> {
64 self.parts.get_field_word(0x08)
65 }
66
67 pub fn access_method(&self) -> Option<AccessMethodData> {
69 self.parts
70 .get_field_byte(0x0A)
71 .map(|raw| AccessMethodData::from(raw))
72 }
73
74 pub fn log_status(&self) -> Option<LogStatus> {
76 self.parts
77 .get_field_byte(0x0B)
78 .map(|raw| LogStatus::from(raw))
79 }
80
81 pub fn log_change_token(&self) -> Option<u32> {
88 self.parts.get_field_dword(0x0C)
89 }
90
91 pub fn access_method_address(&self) -> Option<u32> {
96 self.parts.get_field_dword(0x10)
97 }
98
99 pub fn log_header_format(&self) -> Option<HeaderFormatData> {
101 self.parts
102 .get_field_byte(0x14)
103 .map(|raw| HeaderFormatData::from(raw))
104 }
105
106 pub fn number_of_supported_log_type_descriptors(&self) -> Option<u8> {
112 self.parts.get_field_byte(0x15)
113 }
114
115 pub fn length_of_each_log_type_descriptor(&self) -> Option<u8> {
124 self.parts.get_field_byte(0x16)
125 }
126
127 pub fn type_descriptors(&self) -> Option<TypeDescriptors<'_>> {
129 TypeDescriptors::new(self)
130 }
131}
132
133impl fmt::Debug for SMBiosSystemEventLog<'_> {
134 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
135 fmt.debug_struct(std::any::type_name::<SMBiosSystemEventLog<'_>>())
136 .field("header", &self.parts.header)
137 .field("log_area_length", &self.log_area_length())
138 .field("log_header_start_offset", &self.log_header_start_offset())
139 .field("log_data_start_offset", &self.log_data_start_offset())
140 .field("access_method", &self.access_method())
141 .field("log_status", &self.log_status())
142 .field("log_change_token", &self.log_change_token())
143 .field("access_method_address", &self.access_method_address())
144 .field("log_header_format", &self.log_header_format())
145 .field(
146 "number_of_supported_log_type_descriptors",
147 &self.number_of_supported_log_type_descriptors(),
148 )
149 .field(
150 "length_of_each_log_type_descriptor",
151 &self.length_of_each_log_type_descriptor(),
152 )
153 .field("type_descriptors", &self.type_descriptors())
154 .finish()
155 }
156}
157
158impl Serialize for SMBiosSystemEventLog<'_> {
159 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
160 where
161 S: Serializer,
162 {
163 let mut state = serializer.serialize_struct("SMBiosSystemEventLog", 12)?;
164 state.serialize_field("header", &self.parts.header)?;
165 state.serialize_field("log_area_length", &self.log_area_length())?;
166 state.serialize_field("log_header_start_offset", &self.log_header_start_offset())?;
167 state.serialize_field("log_data_start_offset", &self.log_data_start_offset())?;
168 state.serialize_field("access_method", &self.access_method())?;
169 state.serialize_field("log_status", &self.log_status())?;
170 state.serialize_field("log_change_token", &self.log_change_token())?;
171 state.serialize_field("access_method_address", &self.access_method_address())?;
172 state.serialize_field("log_header_format", &self.log_header_format())?;
173 state.serialize_field(
174 "number_of_supported_log_type_descriptors",
175 &self.number_of_supported_log_type_descriptors(),
176 )?;
177 state.serialize_field(
178 "length_of_each_log_type_descriptor",
179 &self.length_of_each_log_type_descriptor(),
180 )?;
181 state.serialize_field("type_descriptors", &self.type_descriptors())?;
182 state.end()
183 }
184}
185
186pub struct LogTypeData {
188 pub raw: u8,
195 pub value: LogType,
197}
198
199impl fmt::Debug for LogTypeData {
200 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
201 fmt.debug_struct(std::any::type_name::<LogTypeData>())
202 .field("raw", &self.raw)
203 .field("value", &self.value)
204 .finish()
205 }
206}
207
208impl Serialize for LogTypeData {
209 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
210 where
211 S: Serializer,
212 {
213 let mut state = serializer.serialize_struct("LogTypeData", 2)?;
214 state.serialize_field("raw", &self.raw)?;
215 state.serialize_field("value", &self.value)?;
216 state.end()
217 }
218}
219
220impl fmt::Display for LogTypeData {
221 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
222 match &self.value {
223 LogType::None => write!(f, "{}", &self.raw),
224 _ => write!(f, "{:?}", &self.value),
225 }
226 }
227}
228
229impl Deref for LogTypeData {
230 type Target = LogType;
231
232 fn deref(&self) -> &Self::Target {
233 &self.value
234 }
235}
236
237#[derive(Serialize, Debug, PartialEq, Eq)]
239pub enum LogType {
240 SingleBitEccMemoryError,
242 MultiBitEccMemoryError,
244 ParityMemoryError,
246 BusTimeOut,
248 IOChannelCheck,
250 SoftwareNmi,
252 PostMemoryResize,
254 PostError,
256 PciParityError,
258 PciSystemError,
260 CpuFailure,
262 EisaFailSafeTimerTimeout,
264 CorrectableMemoryLogDisabled,
266 LoggingDisabledForSpecificEventType,
268 Reserved0F,
270 SystemLimitExceeded,
272 AsyncHardwareTimerExpired,
274 SystemConfigurationInformation,
276 HardDiskInformation,
278 SystemReconfigured,
280 UncorrectableCpuComplexError,
282 LogAreaReset,
284 SystemBoot,
286 None,
288}
289
290impl From<u8> for LogTypeData {
291 fn from(raw: u8) -> Self {
292 LogTypeData {
293 value: match raw {
294 0x01 => LogType::SingleBitEccMemoryError,
295 0x02 => LogType::MultiBitEccMemoryError,
296 0x03 => LogType::ParityMemoryError,
297 0x04 => LogType::BusTimeOut,
298 0x05 => LogType::IOChannelCheck,
299 0x06 => LogType::SoftwareNmi,
300 0x07 => LogType::PostMemoryResize,
301 0x08 => LogType::PostError,
302 0x09 => LogType::PciParityError,
303 0x0A => LogType::PciSystemError,
304 0x0B => LogType::CpuFailure,
305 0x0C => LogType::EisaFailSafeTimerTimeout,
306 0x0D => LogType::CorrectableMemoryLogDisabled,
307 0x0E => LogType::LoggingDisabledForSpecificEventType,
308 0x0F => LogType::Reserved0F,
309 0x10 => LogType::SystemLimitExceeded,
310 0x11 => LogType::AsyncHardwareTimerExpired,
311 0x12 => LogType::SystemConfigurationInformation,
312 0x13 => LogType::HardDiskInformation,
313 0x14 => LogType::SystemReconfigured,
314 0x15 => LogType::UncorrectableCpuComplexError,
315 0x16 => LogType::LogAreaReset,
316 0x17 => LogType::SystemBoot,
317 _ => LogType::None,
318 },
319 raw,
320 }
321 }
322}
323
324pub struct VariableDataFormatTypeData {
326 pub raw: u8,
333 pub value: VariableDataFormatType,
335}
336
337impl fmt::Debug for VariableDataFormatTypeData {
338 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
339 fmt.debug_struct(std::any::type_name::<VariableDataFormatTypeData>())
340 .field("raw", &self.raw)
341 .field("value", &self.value)
342 .finish()
343 }
344}
345
346impl Serialize for VariableDataFormatTypeData {
347 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
348 where
349 S: Serializer,
350 {
351 let mut state = serializer.serialize_struct("VariableDataFormatTypeData", 2)?;
352 state.serialize_field("raw", &self.raw)?;
353 state.serialize_field("value", &self.value)?;
354 state.end()
355 }
356}
357
358impl fmt::Display for VariableDataFormatTypeData {
359 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
360 match &self.value {
361 VariableDataFormatType::None => write!(f, "{}", &self.raw),
362 _ => write!(f, "{:?}", &self.value),
363 }
364 }
365}
366
367impl Deref for VariableDataFormatTypeData {
368 type Target = VariableDataFormatType;
369
370 fn deref(&self) -> &Self::Target {
371 &self.value
372 }
373}
374
375#[derive(Serialize, Debug, PartialEq, Eq)]
377pub enum VariableDataFormatType {
378 NoStandardFormat,
380 Handle,
382 MultipleEvent,
384 MultipleEventHandle,
386 PostResultsBitmap,
388 SystemManagementType,
390 MultipleEventSystemManagementType,
392 None,
394}
395
396impl From<u8> for VariableDataFormatTypeData {
397 fn from(raw: u8) -> Self {
398 VariableDataFormatTypeData {
399 value: match raw {
400 0x00 => VariableDataFormatType::NoStandardFormat,
401 0x01 => VariableDataFormatType::Handle,
402 0x02 => VariableDataFormatType::MultipleEvent,
403 0x03 => VariableDataFormatType::MultipleEventHandle,
404 0x04 => VariableDataFormatType::PostResultsBitmap,
405 0x05 => VariableDataFormatType::SystemManagementType,
406 0x06 => VariableDataFormatType::MultipleEventSystemManagementType,
407 _ => VariableDataFormatType::None,
408 },
409 raw,
410 }
411 }
412}
413
414pub struct AccessMethodData {
416 pub raw: u8,
423 pub value: AccessMethod,
425}
426
427impl fmt::Debug for AccessMethodData {
428 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
429 fmt.debug_struct(std::any::type_name::<AccessMethodData>())
430 .field("raw", &self.raw)
431 .field("value", &self.value)
432 .finish()
433 }
434}
435
436impl Serialize for AccessMethodData {
437 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
438 where
439 S: Serializer,
440 {
441 let mut state = serializer.serialize_struct("AccessMethodData", 2)?;
442 state.serialize_field("raw", &self.raw)?;
443 state.serialize_field("value", &self.value)?;
444 state.end()
445 }
446}
447
448impl Deref for AccessMethodData {
449 type Target = AccessMethod;
450
451 fn deref(&self) -> &Self::Target {
452 &self.value
453 }
454}
455
456impl From<u8> for AccessMethodData {
457 fn from(raw: u8) -> Self {
458 AccessMethodData {
459 value: AccessMethod::from(raw),
460 raw,
461 }
462 }
463}
464#[derive(Serialize, Debug, PartialEq, Eq)]
468pub enum AccessMethod {
469 IndexedIO18Bit,
474 IndexedIO28Bit,
479 IndexedIO116Bit,
484 MemoryMapped32Bit,
488 GeneralPurposeNonVolatile,
492 None,
494}
495
496impl From<u8> for AccessMethod {
497 fn from(raw: u8) -> Self {
498 match raw {
499 0x00 => AccessMethod::IndexedIO18Bit,
500 0x01 => AccessMethod::IndexedIO28Bit,
501 0x02 => AccessMethod::IndexedIO116Bit,
502 0x03 => AccessMethod::MemoryMapped32Bit,
503 0x04 => AccessMethod::GeneralPurposeNonVolatile,
504 _ => AccessMethod::None,
505 }
506 }
507}
508
509pub struct EventLogTypeDescriptor<'a> {
516 pub raw: &'a [u8],
518}
519
520impl<'a> EventLogTypeDescriptor<'a> {
521 const MINIMUM_RAW_SIZE: usize = 2usize;
522 const LOG_TYPE_OFFSET: usize = 0usize;
523 const VARIABLE_DATA_FORMAT_TYPE_OFFSET: usize = 1usize;
524
525 fn new(raw: &'a [u8]) -> Option<Self> {
526 if raw.len() < Self::MINIMUM_RAW_SIZE {
527 None
528 } else {
529 Some(Self { raw })
530 }
531 }
532
533 pub fn log_type(&self) -> LogTypeData {
535 LogTypeData::from(self.raw[Self::LOG_TYPE_OFFSET])
536 }
537
538 pub fn variable_data_format_type(&self) -> VariableDataFormatTypeData {
544 VariableDataFormatTypeData::from(self.raw[Self::VARIABLE_DATA_FORMAT_TYPE_OFFSET])
545 }
546}
547
548impl<'a> fmt::Debug for EventLogTypeDescriptor<'a> {
549 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
550 fmt.debug_struct(std::any::type_name::<EventLogTypeDescriptor<'_>>())
551 .field("raw", &self.raw)
552 .field("log_type", &self.log_type())
553 .field(
554 "variable_data_format_type",
555 &self.variable_data_format_type(),
556 )
557 .finish()
558 }
559}
560
561impl<'a> Serialize for EventLogTypeDescriptor<'a> {
562 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
563 where
564 S: Serializer,
565 {
566 let mut state = serializer.serialize_struct("EventLogTypeDescriptor", 3)?;
567 state.serialize_field("raw", &self.raw)?;
568 state.serialize_field("log_type", &self.log_type())?;
569 state.serialize_field(
570 "variable_data_format_type",
571 &self.variable_data_format_type(),
572 )?;
573 state.end()
574 }
575}
576
577pub struct TypeDescriptors<'a> {
579 raw: &'a [u8],
580 record_count: usize,
581 record_length: usize,
582}
583
584impl<'a> TypeDescriptors<'a> {
585 fn new(system_event_log: &'a SMBiosSystemEventLog<'a>) -> Option<Self> {
586 system_event_log
587 .length_of_each_log_type_descriptor()
588 .and_then(|record_length| {
589 system_event_log
590 .number_of_supported_log_type_descriptors()
591 .and_then(|record_count| {
592 system_event_log
593 .parts()
594 .get_field_data(
595 SMBiosSystemEventLog::LOG_TYPE_DESCRIPTORS_OFFSET,
596 SMBiosSystemEventLog::LOG_TYPE_DESCRIPTORS_OFFSET
597 + (record_length as usize * record_count as usize),
598 )
599 .and_then(|raw| {
600 Some(Self {
601 raw,
602 record_count: record_count as usize,
603 record_length: record_length as usize,
604 })
605 })
606 })
607 })
608 }
609}
610
611impl<'a> fmt::Debug for TypeDescriptors<'a> {
612 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
613 fmt.debug_struct(std::any::type_name::<TypeDescriptors<'_>>())
614 .field("descriptors", &self.into_iter())
615 .finish()
616 }
617}
618
619impl<'a> Serialize for TypeDescriptors<'a> {
620 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
621 where
622 S: Serializer,
623 {
624 let mut seq = serializer.serialize_seq(Some(self.record_count))?;
625 for e in self {
626 seq.serialize_element(&e)?;
627 }
628 seq.end()
629 }
630}
631
632pub struct TypeDescriptorsIterator<'a> {
634 descriptors: &'a TypeDescriptors<'a>,
635 current_index: usize,
636 current_entry: usize,
637}
638
639impl<'a> TypeDescriptorsIterator<'a> {
640 fn reset(&mut self) {
641 self.current_index = 0;
642 self.current_entry = 0;
643 }
644}
645
646impl<'a> IntoIterator for &'a TypeDescriptors<'a> {
647 type Item = EventLogTypeDescriptor<'a>;
648 type IntoIter = TypeDescriptorsIterator<'a>;
649
650 fn into_iter(self) -> Self::IntoIter {
651 TypeDescriptorsIterator {
652 descriptors: self,
653 current_index: 0,
654 current_entry: 0,
655 }
656 }
657}
658
659impl<'a> Iterator for TypeDescriptorsIterator<'a> {
660 type Item = EventLogTypeDescriptor<'a>;
661
662 fn next(&mut self) -> Option<Self::Item> {
663 if self.current_entry == self.descriptors.record_count {
664 self.reset();
665 return None;
666 }
667
668 let next_index = self.current_index + self.descriptors.record_length;
669 match EventLogTypeDescriptor::new(&self.descriptors.raw[self.current_index..next_index]) {
670 Some(event_log_type_descriptor) => {
671 self.current_index = next_index;
672 self.current_entry += 1;
673 Some(event_log_type_descriptor)
674 }
675 None => {
676 self.reset();
677 None
678 }
679 }
680 }
681}
682
683impl<'a> fmt::Debug for TypeDescriptorsIterator<'a> {
684 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
685 fmt.debug_list()
686 .entries(self.descriptors.into_iter())
687 .finish()
688 }
689}
690
691impl<'a> Serialize for TypeDescriptorsIterator<'a> {
692 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
693 where
694 S: Serializer,
695 {
696 let descriptors: Vec<EventLogTypeDescriptor<'_>> = self.descriptors.into_iter().collect();
697 let mut seq = serializer.serialize_seq(Some(descriptors.len()))?;
698 for e in descriptors {
699 seq.serialize_element(&e)?;
700 }
701 seq.end()
702 }
703}
704
705#[derive(PartialEq, Eq)]
707pub struct LogStatus {
708 pub raw: u8,
710}
711
712impl Deref for LogStatus {
713 type Target = u8;
714
715 fn deref(&self) -> &Self::Target {
716 &self.raw
717 }
718}
719
720impl From<u8> for LogStatus {
721 fn from(raw: u8) -> Self {
722 LogStatus { raw }
723 }
724}
725
726impl LogStatus {
727 pub fn log_area_valid(&self) -> bool {
729 self.raw & 0x01 == 0x01
730 }
731
732 pub fn log_area_full(&self) -> bool {
734 self.raw & 0x02 == 0x02
735 }
736}
737
738impl fmt::Debug for LogStatus {
739 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
740 fmt.debug_struct(std::any::type_name::<LogStatus>())
741 .field("raw", &self.raw)
742 .field("log_area_valid", &self.log_area_valid())
743 .field("log_area_full", &self.log_area_full())
744 .finish()
745 }
746}
747
748impl Serialize for LogStatus {
749 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
750 where
751 S: Serializer,
752 {
753 let mut state = serializer.serialize_struct("LogStatus", 3)?;
754 state.serialize_field("raw", &self.raw)?;
755 state.serialize_field("log_area_valid", &self.log_area_valid())?;
756 state.serialize_field("log_area_full", &self.log_area_full())?;
757 state.end()
758 }
759}
760
761pub struct HeaderFormatData {
763 pub raw: u8,
770 pub value: HeaderFormat,
772}
773
774impl fmt::Debug for HeaderFormatData {
775 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
776 fmt.debug_struct(std::any::type_name::<HeaderFormatData>())
777 .field("raw", &self.raw)
778 .field("value", &self.value)
779 .finish()
780 }
781}
782
783impl Serialize for HeaderFormatData {
784 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
785 where
786 S: Serializer,
787 {
788 let mut state = serializer.serialize_struct("HeaderFormatData", 2)?;
789 state.serialize_field("raw", &self.raw)?;
790 state.serialize_field("value", &self.value)?;
791 state.end()
792 }
793}
794
795impl Deref for HeaderFormatData {
796 type Target = HeaderFormat;
797
798 fn deref(&self) -> &Self::Target {
799 &self.value
800 }
801}
802
803#[derive(Serialize, Debug, PartialEq, Eq)]
805pub enum HeaderFormat {
806 NoHeader,
808 Type1LogHeader,
810 None,
812}
813
814impl From<u8> for HeaderFormatData {
815 fn from(raw: u8) -> Self {
816 HeaderFormatData {
817 value: match raw {
818 0x00 => HeaderFormat::NoHeader,
819 0x01 => HeaderFormat::Type1LogHeader,
820 _ => HeaderFormat::None,
821 },
822 raw,
823 }
824 }
825}
826
827#[cfg(test)]
828mod tests {
829 use super::*;
830
831 #[test]
832 fn unit_test() {
833 let struct_type15 = vec![
834 0x0F, 0x49, 0x3D, 0x00, 0x00, 0x10, 0x00, 0x00, 0x10, 0x00, 0x03, 0x01, 0x05, 0x00,
835 0x00, 0x00, 0x18, 0x20, 0xAE, 0x6A, 0x01, 0x19, 0x02, 0x01, 0x03, 0x02, 0x03, 0x03,
836 0x00, 0x04, 0x00, 0x05, 0x00, 0x06, 0x00, 0x07, 0x00, 0x08, 0x04, 0x09, 0x03, 0x0A,
837 0x03, 0x0B, 0x00, 0x0C, 0x00, 0x0D, 0x00, 0x0E, 0x00, 0x10, 0x00, 0x11, 0x00, 0x12,
838 0x00, 0x13, 0x00, 0x14, 0x00, 0x15, 0x00, 0x16, 0x00, 0x17, 0x00, 0xFF, 0x00, 0xE0,
839 0xE0, 0xE1, 0xE1, 0x00, 0x00,
840 ];
841
842 let parts = UndefinedStruct::new(&struct_type15);
843 let test_struct = SMBiosSystemEventLog::new(&parts);
844
845 println!("{:?}", test_struct);
846 assert_eq!(test_struct.log_area_length(), Some(4096));
847 assert_eq!(test_struct.log_header_start_offset(), Some(0));
848 assert_eq!(test_struct.log_data_start_offset(), Some(16));
849 assert_eq!(
850 *test_struct.access_method().unwrap(),
851 AccessMethod::MemoryMapped32Bit
852 );
853 assert_eq!(
854 test_struct.log_status().unwrap(),
855 LogStatus::from(0b0000_0001)
856 );
857 assert_eq!(test_struct.log_change_token(), Some(5));
858 assert_eq!(test_struct.access_method_address(), Some(1789796376));
859 assert_eq!(
860 *test_struct.log_header_format().unwrap(),
861 HeaderFormat::Type1LogHeader
862 );
863 assert_eq!(
864 test_struct.number_of_supported_log_type_descriptors(),
865 Some(25)
866 );
867 assert_eq!(test_struct.length_of_each_log_type_descriptor(), Some(2));
868
869 let type_descriptors = test_struct.type_descriptors().unwrap();
870 let mut iterator = type_descriptors.into_iter();
871 let first = iterator.next().unwrap();
872 assert_eq!(*first.log_type(), LogType::SingleBitEccMemoryError);
873 }
874}