multiboot2/
smbios.rs

1//! Module for [`SmbiosTag`].
2
3use crate::TagType;
4use crate::tag::TagHeader;
5use core::fmt::Debug;
6use core::mem;
7use multiboot2_common::{MaybeDynSized, Tag};
8#[cfg(feature = "builder")]
9use {alloc::boxed::Box, multiboot2_common::new_boxed};
10
11/// This tag contains a copy of SMBIOS tables as well as their version.
12#[derive(ptr_meta::Pointee, PartialEq, Eq, PartialOrd, Ord, Hash)]
13#[repr(C, align(8))]
14pub struct SmbiosTag {
15    header: TagHeader,
16    major: u8,
17    minor: u8,
18    _reserved: [u8; 6],
19    tables: [u8],
20}
21
22impl SmbiosTag {
23    /// Constructs a new tag.
24    #[cfg(feature = "builder")]
25    #[must_use]
26    pub fn new(major: u8, minor: u8, tables: &[u8]) -> Box<Self> {
27        let header = TagHeader::new(Self::ID, 0);
28        let reserved = [0, 0, 0, 0, 0, 0];
29        new_boxed(header, &[&[major, minor], &reserved, tables])
30    }
31
32    /// Returns the major number.
33    #[must_use]
34    pub const fn major(&self) -> u8 {
35        self.major
36    }
37
38    /// Returns the major number.
39    #[must_use]
40    pub const fn minor(&self) -> u8 {
41        self.minor
42    }
43
44    /// Returns the raw tables.
45    #[must_use]
46    pub const fn tables(&self) -> &[u8] {
47        &self.tables
48    }
49}
50
51impl MaybeDynSized for SmbiosTag {
52    type Header = TagHeader;
53
54    const BASE_SIZE: usize = mem::size_of::<TagHeader>() + mem::size_of::<u8>() * 8;
55
56    fn dst_len(header: &TagHeader) -> usize {
57        assert!(header.size as usize >= Self::BASE_SIZE);
58        header.size as usize - Self::BASE_SIZE
59    }
60}
61
62impl Tag for SmbiosTag {
63    type IDType = TagType;
64
65    const ID: TagType = TagType::Smbios;
66}
67
68impl Debug for SmbiosTag {
69    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
70        f.debug_struct("BootLoaderNameTag")
71            .field("typ", &self.header.typ)
72            .field("size", &self.header.size)
73            .field("major", &self.major)
74            .field("minor", &self.minor)
75            .finish()
76    }
77}
78
79#[cfg(test)]
80mod tests {
81    use super::*;
82    use crate::GenericInfoTag;
83    use core::borrow::Borrow;
84    use multiboot2_common::test_utils::AlignedBytes;
85
86    #[rustfmt::skip]
87    fn get_bytes() -> AlignedBytes<32> {
88        AlignedBytes::new([
89            TagType::Smbios.val() as u8, 0, 0, 0,
90            25, 0, 0, 0,
91            /* major */
92            7,
93            /* minor */
94            42,
95            /* reserved */
96            0, 0, 0, 0, 0, 0,
97            /* table data */
98            0, 1, 2, 3, 4, 5, 6, 7, 8,
99            /* padding */
100            0, 0, 0, 0, 0, 0, 0
101        ])
102    }
103
104    /// Test to parse a given tag.
105    #[test]
106    fn test_parse() {
107        let bytes = get_bytes();
108        let tag = GenericInfoTag::ref_from_slice(bytes.borrow()).unwrap();
109        let tag = tag.cast::<SmbiosTag>();
110        assert_eq!(tag.header.typ, TagType::Smbios);
111        assert_eq!(tag.major, 7);
112        assert_eq!(tag.minor, 42);
113        assert_eq!(&tag.tables, [0, 1, 2, 3, 4, 5, 6, 7, 8]);
114    }
115
116    /// Test to generate a tag.
117    #[test]
118    #[cfg(feature = "builder")]
119    fn test_build() {
120        let tag = SmbiosTag::new(7, 42, &[0, 1, 2, 3, 4, 5, 6, 7, 8]);
121        let bytes = tag.as_bytes().as_ref();
122        let bytes = &bytes[..tag.header.size as usize];
123        assert_eq!(bytes, &get_bytes()[..tag.header.size as usize]);
124    }
125}