dmidecode/structures/015_system_event_log/
mod.rs

1//! System Event Log (Type 15)
2//!
3//! The presence of this structure within the SMBIOS data returned for a system indicates that the
4//! system supports an event log. An event log is a fixed-length area within a non-volatile storage
5//! element, starting with a fixed-length (and vendor-specific) header record, followed by one or
6//! more variable-length log records.\
7//! An application can implement event-log change notification by periodically reading the System
8//! Event Log structure (by its assigned handle) and looking for a change in the Log Change Token.
9//! This token uniquely identifies the last time the event log was updated. When it sees the token
10//! changed, the application can retrieve the entire event log and determine the changes since the
11//! last time it read the event log.
12
13use core::convert::TryInto;
14use core::fmt;
15use core::hash::{Hash, Hasher};
16use core::slice::Chunks;
17
18use crate::{
19    bitfield::{BitField, FlagType, Layout},
20    InfoType,
21    MalformedStructureError::{self, InvalidFormattedSectionLength},
22    RawStructure,
23};
24
25pub mod log_record_format;
26pub use self::log_record_format::{EventLogType, VariableDataFormatType};
27
28/// Main struct for *System Event Log (Type 15) structure*
29#[derive(Clone, Debug, Eq, Hash, PartialEq)]
30pub struct SystemEventLog<'a> {
31    /// Specifies the structure’s handle
32    pub handle: u16,
33    /// Length, in bytes, of the overall event log area, from the first byte of header to the last
34    /// byte of data
35    pub log_area_length: u16,
36    /// Defines the starting offset (or index) within the nonvolatile storage of the event-log’s
37    /// header, from the Access Method Address For single-byte indexed I/O accesses, the
38    /// most-significant byte of the start offset is set to 00h.
39    pub log_header_start_offset: u16,
40    /// Defines the starting offset (or index) within the nonvolatile storage of the event-log’s
41    /// first data byte, from the Access Method Address For single-byte indexed I/O accesses, the
42    /// most-significant byte of the start offset is set to 00h.
43    pub log_data_start_offset: u16,
44    pub access_method: AccessMethod,
45    pub log_status: LogStatus,
46    /// Unique token that is reassigned every time the event log changes Can be used to determine
47    /// if additional events have occurred since the last time the log was read.
48    pub log_change_token: u32,
49    /// Format of the log header area
50    pub log_header_format: Option<LogHeaderFormat>,
51    /// List of Supported Event Log Type Descriptors
52    pub supported_event_log_type_descriptors: Option<SupportedEventLogTypeDescriptors<'a>>,
53}
54
55/// Defines the Location and Method used by higher-level software to access the log area.
56///
57/// Each variant contains address associated with the access method.
58#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
59pub enum AccessMethod {
60    /// Indexed I/O: 1 8-bit index port, 1 8-bit data port.
61    IndexedIoOne8bitIndexOne8bitData { index: u8, data: u8 },
62    /// Indexed I/O: 2 8-bit index ports, 1 8-bit data port.
63    IndexedIoTwo8bitIndexOne8bitData { index: [u8; 2], data: u8 },
64    /// Indexed I/O: 1 16-bit index port, 1 8-bit data port.
65    IndexedIoOne16bitIndexOne8bitData { index: u16, data: u8 },
66    /// Memory-mapped physical 32-bit address.
67    MemoryMappedPhysicaAddress { physical_address: u32 },
68    /// Available through General-Purpose NonVolatile Data functions.
69    GeneralPurposeNonVolatileData { gpnv_handle: u16 },
70    /// Available for future assignment
71    Available { method: u8, address: u32 },
72    /// BIOS Vendor/OEM-specific
73    OemSpecific { method: u8, address: u32 },
74}
75
76/// Current status of the system event-log
77///
78/// The Log Status fields might not be up-to-date (dynamic) when the structure is accessed using
79/// the table interface.
80#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
81pub struct LogStatus(u8);
82
83/// Identify the standard formats of the event log headers.
84#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
85pub enum LogHeaderFormat {
86    /// No header (for example, the header is 0 bytes in length)
87    NoHeader,
88    /// Type 1 log header
89    LogHeaderType1,
90    /// Available for future assignment
91    Available(u8),
92    /// BIOS Vendor/OEM-specific
93    OemSpecific(u8),
94}
95
96///// The type 1 event log header
97//#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
98//pub struct LogHeaderType1 {
99//    /// Reserved area for OEM customization, not assignable by SMBIOS specification
100//    pub oem_reserved: [u8; 5],
101//    pub multiple_event: MultipleEvent,
102//    pub pre_boot_event_log_reset: PreBootEventLogReset,
103//    pub cmos_checksum: CmosChecksum,
104//    /// Available for future assignment
105//    pub reserved: [u8; 3],
106//    /// Version of Type 1 header implemented
107//    pub header_revision: u8,
108//}
109//#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
110//pub struct MultipleEvent {
111//    /// Number of minutes that must pass between duplicate log entries that utilize a
112//    /// multiple-event counter, specified in BCD The value ranges from 00h to 99h to represent 0 to
113//    /// 99 minutes.
114//    pub time_window: u8,
115//    /// Number of occurrences of a duplicate event that must pass before the multiple-event counter
116//    /// associated with the log entry is updated, specified as a numeric value in the range 1 to
117//    /// 255 (The value 0 is reserved.)
118//    pub count_increment: u8,
119//}
120//#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
121//pub struct PreBootEventLogReset {
122//    /// CMOS RAM address (in the range 10h - FFh) associated with the Pre-boot Event Log Reset.
123//    pub cmos_address: u8,
124//    /// Bit within the above CMOS RAM location that is set to indicate that the log should be
125//    /// cleared.
126//    pub cmos_bit_index: u8,
127//}
128//#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
129//pub struct CmosChecksum {
130//    /// CMOS RAM address associated with the start of the area that is to be checksummed
131//    pub starting_offset: u8,
132//    /// Number of consecutive CMOS RAM addresses
133//    pub byte_count: u8,
134//    /// CMOS RAM address associated with the start of two consecutive bytes into which the
135//    /// calculated checksum value is stored.
136//    pub checksum_offset: u8,
137//}
138
139/// An iterator through Event Log Type Descriptors
140#[derive(Clone, Debug)]
141pub struct SupportedEventLogTypeDescriptors<'a>(Chunks<'a, u8>);
142
143/// Supported Event Log Type descriptor
144///
145/// The presence of an entry identifies that the Log Type is supported by the system and the format
146/// of any variable data that accompanies the first bytes of the log’s variable data — a specific
147/// log record might have more variable data than specified by its Variable Data Format Type.
148#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
149pub struct EventLogTypeDescriptor {
150    pub log_type: EventLogType,
151    pub variable_data_format_type: VariableDataFormatType,
152}
153
154impl<'a> SystemEventLog<'a> {
155    pub(crate) fn try_from(structure: RawStructure<'a>) -> Result<Self, MalformedStructureError> {
156        let handle = structure.handle;
157        let number_of_supported_log_type_descriptors = structure.get::<u8>(0x15).ok();
158        let length_of_each_log_type_descriptor = structure.get::<u8>(0x16).ok();
159        let len_gt_2_1 = number_of_supported_log_type_descriptors
160            .and_then(|x| length_of_each_log_type_descriptor.map(|y| 0x17 + x as usize * y as usize));
161        match (
162            (structure.version.major, structure.version.minor),
163            structure.data.len() + 4,
164        ) {
165            (v, l) if v == (2, 0) && l != 0x14 => Err(InvalidFormattedSectionLength(
166                InfoType::SystemEventLog,
167                handle,
168                "",
169                0x14,
170            )),
171            (v, l) if v >= (2, 1) && Some(l) != len_gt_2_1 => {
172                if let Some(len) = len_gt_2_1 {
173                    Err(InvalidFormattedSectionLength(
174                        InfoType::SystemEventLog,
175                        handle,
176                        "17h+(x*y) = ",
177                        len as u8,
178                    ))
179                } else {
180                    Err(InvalidFormattedSectionLength(
181                        InfoType::SystemEventLog,
182                        handle,
183                        "minimum of ",
184                        0,
185                    ))
186                }
187            }
188            _ => {
189                let access_method = {
190                    let method = structure.get::<u8>(0x0A)?;
191                    let address = structure.get::<u32>(0x10)?;
192                    AccessMethod::new(method, address)
193                };
194                let supported_event_log_type_descriptors = (|| {
195                    let number = number_of_supported_log_type_descriptors? as usize;
196                    let length = length_of_each_log_type_descriptor? as usize;
197                    let data = structure.get_slice(0x17, number * length)?;
198                    Some(SupportedEventLogTypeDescriptors::new(data, length))
199                })();
200                Ok(Self {
201                    handle,
202                    log_area_length: structure.get::<u16>(0x04)?,
203                    log_header_start_offset: structure.get::<u16>(0x06)?,
204                    log_data_start_offset: structure.get::<u16>(0x08)?,
205                    access_method,
206                    log_status: structure.get::<u8>(0x0B)?.into(),
207                    log_change_token: structure.get::<u32>(0x0C)?,
208                    log_header_format: structure.get::<u8>(0x14).ok().map(Into::into),
209                    supported_event_log_type_descriptors,
210                })
211            }
212        }
213    }
214}
215
216impl AccessMethod {
217    /// According to [Table 62](https://www.dmtf.org/sites/default/files/standards/documents/DSP0134_3.4.0.pdf)
218    /// ## Access Method Address: DWORD layout
219    ///
220    /// | Access Type           | BYTE 3   | BYTE 2   | BYTE 1     | BYTE 0     |
221    /// |-----------------------|----------|----------|------------|------------|
222    /// | 00:02 – Indexed I/O   | Data MSB | Data LSB | Index MSB  | Index LSB  |
223    /// | 03 – Absolute Address | Byte 3   | Byte 2   | Byte 1     | Byte 0     |
224    /// | Use GPNV              | 0        | 0        | Handle MSB | Handle LSB |
225    ///
226    pub fn new(method: u8, address: u32) -> Self {
227        let [index_lsb, index_msb, data_lsb, _data_msb] = u32::to_le_bytes(address);
228        match method {
229            0x00 => Self::IndexedIoOne8bitIndexOne8bitData {
230                index: index_lsb,
231                data: data_lsb,
232            },
233            0x01 => Self::IndexedIoTwo8bitIndexOne8bitData {
234                index: [index_lsb, index_msb],
235                data: data_lsb,
236            },
237            0x02 => Self::IndexedIoOne16bitIndexOne8bitData {
238                index: u16::from_le_bytes([index_lsb, index_msb]),
239                data: data_lsb,
240            },
241            0x03 => Self::MemoryMappedPhysicaAddress {
242                physical_address: address,
243            },
244            0x04 => Self::GeneralPurposeNonVolatileData {
245                gpnv_handle: u16::from_le_bytes([index_lsb, index_msb]),
246            },
247            method @ 0x80..=0xFF => Self::OemSpecific { method, address },
248            method => Self::Available { method, address },
249        }
250    }
251    pub fn address(&self) -> u32 {
252        match self {
253            Self::IndexedIoOne8bitIndexOne8bitData { index, data } => u32::from_le_bytes([*index, 0, *data, 0]),
254            Self::IndexedIoTwo8bitIndexOne8bitData { index, data } => {
255                u32::from_le_bytes([index[0], index[1], *data, 0])
256            }
257            Self::IndexedIoOne16bitIndexOne8bitData { index, data } => {
258                let index = u16::to_le_bytes(*index);
259                u32::from_le_bytes([index[0], index[1], *data, 0])
260            }
261            Self::MemoryMappedPhysicaAddress { physical_address } => *physical_address,
262            Self::GeneralPurposeNonVolatileData { gpnv_handle } => *gpnv_handle as u32,
263            Self::OemSpecific { address, .. } => *address,
264            Self::Available { address, .. } => *address,
265        }
266    }
267}
268impl fmt::Display for AccessMethod {
269    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
270        match (f.alternate(), self) {
271            (false, Self::IndexedIoOne8bitIndexOne8bitData { .. }) => {
272                write!(f, "Indexed I/O, one 8-bit index port, one 8-bit data port")
273            }
274            (false, Self::IndexedIoTwo8bitIndexOne8bitData { .. }) => {
275                write!(f, "Indexed I/O, two 8-bit index ports, one 8-bit data port")
276            }
277            (false, Self::IndexedIoOne16bitIndexOne8bitData { .. }) => {
278                write!(f, "Indexed I/O, one 16-bit index port, one 8-bit data port")
279            }
280            (false, Self::MemoryMappedPhysicaAddress { .. }) => write!(f, "Memory-mapped physical 32-bit address"),
281            (false, Self::GeneralPurposeNonVolatileData { .. }) => {
282                write!(f, "General-purpose non-volatile data functions")
283            }
284            (false, Self::OemSpecific { method, .. }) => write!(f, "OEM-specific: {}", method),
285            (false, Self::Available { method, .. }) => write!(f, "Available: {}", method),
286            // With address
287            (true, Self::IndexedIoOne8bitIndexOne8bitData { index, data }) => write!(
288                f,
289                "Indexed I/O, one 8-bit index port, one 8-bit data port: Index 0x{:02X}, Data 0x{:02X}",
290                index, data
291            ),
292            (true, Self::IndexedIoTwo8bitIndexOne8bitData { index, data }) => write!(
293                f,
294                "Indexed I/O, two 8-bit index ports, one 8-bit data port: Index {:X?}, Data 0x{:02X}",
295                index, data
296            ),
297            (true, Self::IndexedIoOne16bitIndexOne8bitData { index, data }) => write!(
298                f,
299                "Indexed I/O, one 16-bit index port, one 8-bit data port: Index 0x{:04X}, Data 0x{:02X}",
300                index, data
301            ),
302            (true, Self::MemoryMappedPhysicaAddress { physical_address }) => {
303                write!(f, "Memory-mapped physical 32-bit address: 0x{:08X}", physical_address)
304            }
305            (true, Self::GeneralPurposeNonVolatileData { gpnv_handle }) => write!(
306                f,
307                "General-Purpose NonVolatile Data functions, handle 0x{:04X}",
308                gpnv_handle
309            ),
310            (true, Self::OemSpecific { method, address }) => write!(
311                f,
312                "BIOS Vendor/OEM-specific: Method {}, Address 0x{:08X}",
313                method, address
314            ),
315            (true, Self::Available { method, address }) => {
316                write!(f, "Available: Method {}, Address 0x{:08X}", method, address)
317            }
318        }
319    }
320}
321
322impl BitField<'_> for LogStatus {
323    type Size = u8;
324    fn value(&self) -> Self::Size {
325        self.0
326    }
327    layout!(
328        length = 8;
329        "Valid" "Log area valid",
330        "Full" "Log area full",
331        "Reserved": 6,
332    );
333}
334impl From<u8> for LogStatus {
335    fn from(byte: u8) -> Self {
336        Self(byte)
337    }
338}
339
340impl From<u8> for LogHeaderFormat {
341    fn from(byte: u8) -> Self {
342        match byte {
343            0x00 => Self::NoHeader,
344            0x01 => Self::LogHeaderType1,
345            v @ 0x80..=0xFF => Self::OemSpecific(v),
346            v => Self::Available(v),
347        }
348    }
349}
350impl fmt::Display for LogHeaderFormat {
351    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
352        match (f.alternate(), self) {
353            (_, Self::NoHeader) => write!(f, "No Header"),
354            (true, Self::LogHeaderType1) => write!(f, "Type 1 log header"),
355            (false, Self::LogHeaderType1) => write!(f, "Type 1"),
356            (true, Self::OemSpecific(v)) => write!(f, "BIOS vendor or OEM-specific format: {}", v),
357            (false, Self::OemSpecific(_)) => write!(f, "OEM-specific"),
358            (_, Self::Available(v)) => write!(f, "Available: {}", v),
359        }
360    }
361}
362
363impl<'a> SupportedEventLogTypeDescriptors<'a> {
364    fn new(data: &'a [u8], size: usize) -> Self {
365        Self(data.chunks(size))
366    }
367}
368impl PartialEq for SupportedEventLogTypeDescriptors<'_> {
369    fn eq(&self, other: &Self) -> bool {
370        self.0.clone().eq(other.0.clone())
371    }
372}
373impl Eq for SupportedEventLogTypeDescriptors<'_> {}
374impl Hash for SupportedEventLogTypeDescriptors<'_> {
375    fn hash<H: Hasher>(&self, state: &mut H) {
376        self.0.clone().for_each(|c| c.hash(state));
377    }
378}
379impl Iterator for SupportedEventLogTypeDescriptors<'_> {
380    type Item = EventLogTypeDescriptor;
381
382    fn next(&mut self) -> Option<Self::Item> {
383        let next = self.0.next()?;
384        next.try_into().ok().map(|a: [u8; 2]| EventLogTypeDescriptor {
385            log_type: a[0].into(),
386            variable_data_format_type: a[1].into(),
387        })
388    }
389}
390
391impl From<[u8; 2]> for EventLogTypeDescriptor {
392    fn from(a: [u8; 2]) -> Self {
393        Self {
394            log_type: a[0].into(),
395            variable_data_format_type: a[1].into(),
396        }
397    }
398}
399impl From<EventLogTypeDescriptor> for [u8; 2] {
400    fn from(d: EventLogTypeDescriptor) -> Self {
401        [d.log_type.into(), d.variable_data_format_type.into()]
402    }
403}
404
405#[cfg(test)]
406mod tests {
407    use pretty_assertions::assert_eq;
408    use std::prelude::v1::*;
409
410    #[test]
411    fn access_method() {
412        use super::AccessMethod;
413
414        let address = u32::from_le_bytes([0x78, 0x56, 0x34, 0x12]);
415        let data = &[
416            (
417                0,
418                "Indexed I/O, one 8-bit index port, one 8-bit data port: Index 0x78, Data 0x34",
419            ),
420            (
421                1,
422                "Indexed I/O, two 8-bit index ports, one 8-bit data port: Index [78, 56], Data 0x34",
423            ),
424            (
425                2,
426                "Indexed I/O, one 16-bit index port, one 8-bit data port: Index 0x5678, Data 0x34",
427            ),
428            (3, "Memory-mapped physical 32-bit address: 0x12345678"),
429            (4, "General-Purpose NonVolatile Data functions, handle 0x5678"),
430            (5, "Available: Method 5, Address 0x12345678"),
431            (0x80, "BIOS Vendor/OEM-specific: Method 128, Address 0x12345678"),
432        ];
433        for (m, s) in data {
434            assert_eq!(*s, format!("{:#}", AccessMethod::new(*m, address)));
435        }
436    }
437
438    #[test]
439    fn log_status() {
440        use super::LogStatus;
441        use crate::bitfield::BitField;
442
443        let byte: u8 = 0b111;
444        let ls: LogStatus = byte.into();
445        let sample = vec!["Log area valid", "Log area full"];
446        assert_eq!(
447            sample,
448            ls.significants().map(|v| format!("{:#}", v)).collect::<Vec<_>>()
449        );
450    }
451
452    #[test]
453    fn log_header_format() {
454        use super::LogHeaderFormat;
455
456        let data = &[
457            (0u8, "No Header"),
458            (1, "Type 1 log header"),
459            (2, "Available: 2"),
460            (0xFF, "BIOS vendor or OEM-specific format: 255"),
461        ];
462        for (v, s) in data {
463            assert_eq!(*s, format!("{:#}", LogHeaderFormat::from(*v)));
464        }
465    }
466
467    #[test]
468    fn supported_event_log_type_descriptors() {
469        use super::{
470            EventLogType as T, EventLogTypeDescriptor as Desc, SupportedEventLogTypeDescriptors,
471            VariableDataFormatType as D,
472        };
473
474        let data = &[
475            0x02, 0x00, 0x04, 0x01, 0x08, 0x02, 0x16, 0x03, 0x66, 0x00, 0xEE, 0x00, 0xFF, 0x00,
476        ];
477        let sample = vec![
478            Desc {
479                log_type: T::MultiBitEccMemoryError,
480                variable_data_format_type: D::None,
481            },
482            Desc {
483                log_type: T::BusTimeOut,
484                variable_data_format_type: D::Handle { handle: 0 },
485            },
486            Desc {
487                log_type: T::PostError,
488                variable_data_format_type: D::MultipleEvent { counter: 0 },
489            },
490            Desc {
491                log_type: T::LogAreaReset,
492                variable_data_format_type: D::MultipleEventHandle { handle: 0, counter: 0 },
493            },
494            Desc {
495                log_type: T::Unused(0x66),
496                variable_data_format_type: D::None,
497            },
498            Desc {
499                log_type: T::Available(0xEE),
500                variable_data_format_type: D::None,
501            },
502            Desc {
503                log_type: T::EndOfLog,
504                variable_data_format_type: D::None,
505            },
506        ];
507        let result = SupportedEventLogTypeDescriptors::new(data, 2);
508        assert_eq!(sample, result.collect::<Vec<_>>());
509    }
510
511    #[test]
512    fn system_event_log() {
513        use super::EventLogType as T;
514        use super::VariableDataFormatType as D;
515        use super::*;
516        use crate::{bitfield::Position, InfoType, RawStructure};
517
518        let length = 77 - 4;
519        let (data, strings) =
520            include_bytes!("../../../tests/data/02daadcd/entries/15-0/bin")[4..].split_at(length as usize);
521        let structure = RawStructure {
522            version: (2, 7).into(),
523            info: InfoType::SystemEventLog,
524            length,
525            handle: 0x0036,
526            data,
527            strings,
528        };
529        let result = SystemEventLog::try_from(structure).unwrap();
530
531        let access_method = AccessMethod::MemoryMappedPhysicaAddress {
532            physical_address: 0xFFC40000,
533        };
534        assert_eq!(access_method, result.access_method, "AccessMethod");
535
536        let log_status = [Position(0)].iter().collect::<u8>().into();
537        assert_eq!(log_status, result.log_status, "LogStatus");
538
539        let seltd_length = result.supported_event_log_type_descriptors.clone().unwrap().count();
540        assert_eq!(27, seltd_length, "Supported Log Type Descriptors count");
541
542        let seltd_sample = [
543            (T::SingleBitEccMemoryError, D::None),
544            (T::MultiBitEccMemoryError, D::None),
545            (T::ParityMemoryError, D::None),
546            (T::BusTimeOut, D::None),
547            (T::IoChannelCheck, D::None),
548            (T::SoftwareNmi, D::None),
549            (T::PostMemoryResize, D::None),
550            (T::PostError, D::PostResults(0.into())),
551            (T::PciParityError, D::None),
552            (T::PciSystemError, D::None),
553            (T::CpuFailure, D::None),
554            (T::EisaFailSafeTimerTimeOut, D::None),
555            (T::CorrectableMemoryLogDisabled, D::None),
556            (T::LoggingDisabledForSpecificEventType, D::None),
557            (T::SystemLimitExceeded, D::None),
558            (T::AsynchronousHardwareTimerExpired, D::None),
559            (T::SystemConfigurationInformation, D::None),
560            (T::HardDiskInformation, D::None),
561            (T::SystemReconfigured, D::None),
562            (T::UncorrectableCpuComplexError, D::None),
563            (T::LogAreaReset, D::None),
564            (T::SystemBoot, D::None),
565            (T::EndOfLog, D::None),
566            (T::Available(0xB0), D::OemAssigned(0xB0)),
567            (T::Available(0xB1), D::OemAssigned(0xB1)),
568            (T::Available(0xE0), D::OemAssigned(0xE0)),
569            (T::Available(0xE1), D::OemAssigned(0xE1)),
570        ]
571        .iter()
572        .map(|(t, d)| EventLogTypeDescriptor {
573            log_type: *t,
574            variable_data_format_type: *d,
575        })
576        .collect::<Vec<_>>();
577        let seltd_result = result
578            .supported_event_log_type_descriptors
579            .clone()
580            .unwrap()
581            .collect::<Vec<_>>();
582        assert_eq!(seltd_sample, seltd_result, "SupportedEventLogTypeDescriptors");
583
584        let sample_bytes = seltd_sample.iter().fold(Vec::new(), |mut vec: Vec<u8>, eltd| {
585            vec.push(eltd.log_type.into());
586            vec.push(eltd.variable_data_format_type.into());
587            vec
588        });
589        let sample = SystemEventLog {
590            handle: 0x0036,
591            log_area_length: 16383,
592            log_header_start_offset: 0x0000,
593            log_data_start_offset: 0x0010,
594            access_method,
595            log_status,
596            log_change_token: 0x00000001,
597            log_header_format: Some(LogHeaderFormat::LogHeaderType1),
598            supported_event_log_type_descriptors: Some(SupportedEventLogTypeDescriptors::new(&sample_bytes, 2)),
599        };
600        assert_eq!(sample, result, "SystemEventLog");
601    }
602}