smbioslib/structs/types/
tpm_device.rs

1use crate::core::{strings::*, UndefinedStruct};
2use crate::SMBiosStruct;
3use serde::{ser::SerializeStruct, Serialize, Serializer};
4use std::{array::TryFromSliceError, convert::TryFrom, fmt, ops::Deref};
5
6/// # TPM Device (Type 43)
7pub struct SMBiosTpmDevice<'a> {
8    parts: &'a UndefinedStruct,
9}
10
11impl<'a> SMBiosStruct<'a> for SMBiosTpmDevice<'a> {
12    const STRUCT_TYPE: u8 = 43u8;
13
14    fn new(parts: &'a UndefinedStruct) -> Self {
15        Self { parts }
16    }
17
18    fn parts(&self) -> &'a UndefinedStruct {
19        self.parts
20    }
21}
22
23impl<'a> SMBiosTpmDevice<'a> {
24    /// Vendor Id
25    ///
26    /// Specified as four ASCII characters, as defined by TCG
27    /// Vendor ID (see CAP_VID in TCG Vendor ID Registry).
28    ///
29    /// For example:
30    /// Vendor ID string of "ABC" = (41 42 43 00)
31    /// Vendor ID string of "ABCD" = (41 42 43 44)
32    pub fn vendor_id(&self) -> Option<VendorId<'_>> {
33        self.parts
34            .get_field_data(0x04, 0x08)
35            .and_then(|array| Some(VendorId::try_from(array).expect("Vendor Id is 4 bytes")))
36    }
37
38    /// Major spec version
39    ///
40    /// Major TPM version supported by the TPM device. For
41    /// example, the value is 01h for TPM v1.2 and is 02h for
42    /// TPM v2.0.
43    pub fn major_spec_version(&self) -> Option<u8> {
44        self.parts.get_field_byte(0x08)
45    }
46
47    /// Minor spec version
48    ///
49    /// Minor TPM version supported by the TPM device. For
50    /// example, the value is 02h for TPM v1.2 and is 00h for
51    /// TPM v2.0.
52    pub fn minor_spec_version(&self) -> Option<u8> {
53        self.parts.get_field_byte(0x09)
54    }
55
56    /// Firmware version 1
57    ///
58    /// For Major Spec Version 01h, this field contains the
59    /// TPM_VERSION structure defined in the TPM Main
60    /// Specification, Part 2, Section 5.3.
61    ///
62    /// For Major Spec Version 02h, this field contains the
63    /// most significant 32 bits of a TPM vendor-specific value
64    /// for firmware version (see
65    /// TPM_PT_FIRMWARE_VERSION_1 in TPM Structures
66    /// specification).
67    pub fn firmware_version_1(&self) -> Option<u32> {
68        self.parts.get_field_dword(0x0A)
69    }
70
71    /// Firmware version 2
72    ///
73    /// For Major Spec Version 01h, this field contains 00h.
74    ///
75    /// For Major Spec Version 02h, this field contains the
76    /// least significant 32 bits of a TPM vendor-specific value
77    /// for firmware version (see
78    /// TPM_PT_FIRMWARE_VERSION_2 in TPM Structures
79    /// specification).
80    pub fn firmware_version_2(&self) -> Option<u32> {
81        self.parts.get_field_dword(0x0E)
82    }
83
84    /// Description
85    ///
86    /// Descriptive information of the TPM device.
87    pub fn description(&self) -> SMBiosString {
88        self.parts.get_field_string(0x12)
89    }
90
91    /// Characteristics
92    ///
93    /// TPM device characteristics information.
94    pub fn characteristics(&self) -> Option<TpmDeviceCharacteristics> {
95        self.parts
96            .get_field_qword(0x13)
97            .map(|raw| TpmDeviceCharacteristics::from(raw))
98    }
99
100    /// OEM defined
101    ///
102    /// OEM- or BIOS vendor-specific information
103    pub fn oem_defined(&self) -> Option<u32> {
104        self.parts.get_field_dword(0x1B)
105    }
106}
107
108impl fmt::Debug for SMBiosTpmDevice<'_> {
109    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
110        fmt.debug_struct(std::any::type_name::<SMBiosTpmDevice<'_>>())
111            .field("header", &self.parts.header)
112            .field("vendor_id", &self.vendor_id())
113            .field("major_spec_version", &self.major_spec_version())
114            .field("minor_spec_version", &self.minor_spec_version())
115            .field("firmware_version_1", &self.firmware_version_1())
116            .field("firmware_version_2", &self.firmware_version_2())
117            .field("description", &self.description())
118            .field("characteristics", &self.characteristics())
119            .field("oem_defined", &self.oem_defined())
120            .finish()
121    }
122}
123
124impl Serialize for SMBiosTpmDevice<'_> {
125    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
126    where
127        S: Serializer,
128    {
129        let mut state = serializer.serialize_struct("SMBiosTpmDevice", 9)?;
130        state.serialize_field("header", &self.parts.header)?;
131        state.serialize_field("vendor_id", &self.vendor_id())?;
132        state.serialize_field("major_spec_version", &self.major_spec_version())?;
133        state.serialize_field("minor_spec_version", &self.minor_spec_version())?;
134        state.serialize_field("firmware_version_1", &self.firmware_version_1())?;
135        state.serialize_field("firmware_version_2", &self.firmware_version_2())?;
136        state.serialize_field("description", &self.description())?;
137        state.serialize_field("characteristics", &self.characteristics())?;
138        state.serialize_field("oem_defined", &self.oem_defined())?;
139        state.end()
140    }
141}
142
143/// # Vendor Id
144///
145/// Specified as four ASCII characters,
146/// as defined by TCG Vendor ID
147/// (see CAP_VID in TCG Vendor ID Registry)
148#[derive(PartialEq, Eq)]
149pub struct VendorId<'a> {
150    /// Raw array
151    ///
152    /// Example: Vendor Id string of "ABC" = (41 42 43 00)
153    pub array: &'a [u8; 4],
154}
155
156impl<'a> TryFrom<&'a [u8]> for VendorId<'a> {
157    type Error = TryFromSliceError;
158
159    fn try_from(raw: &'a [u8]) -> Result<Self, Self::Error> {
160        <&[u8; 4]>::try_from(raw).and_then(|array| Ok(VendorId { array }))
161    }
162}
163
164impl<'a> fmt::Debug for VendorId<'a> {
165    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
166        fmt.debug_struct(std::any::type_name::<VendorId<'_>>())
167            .field("array", &self.array)
168            .field("string", &String::from_utf8_lossy(self.array))
169            .finish()
170    }
171}
172
173impl<'a> Serialize for VendorId<'a> {
174    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
175    where
176        S: Serializer,
177    {
178        let mut state = serializer.serialize_struct("VendorId", 2)?;
179        state.serialize_field("array", &self.array)?;
180        state.serialize_field("string", &String::from_utf8_lossy(self.array))?;
181        state.end()
182    }
183}
184
185/// # TPM Device Characteristics
186#[derive(PartialEq, Eq)]
187pub struct TpmDeviceCharacteristics {
188    /// Raw value
189    ///
190    /// _raw_ is useful when there are values not yet defiend.
191    /// This is most likely to occur when the standard was updated but
192    /// this library code has not been updated to match the current
193    /// standard.
194    pub raw: u64,
195}
196
197impl Deref for TpmDeviceCharacteristics {
198    type Target = u64;
199
200    fn deref(&self) -> &Self::Target {
201        &self.raw
202    }
203}
204
205impl From<u64> for TpmDeviceCharacteristics {
206    fn from(raw: u64) -> Self {
207        TpmDeviceCharacteristics { raw }
208    }
209}
210
211impl TpmDeviceCharacteristics {
212    /// Bit 0 - reserved
213    pub fn reserved_0(&self) -> bool {
214        self.raw & 0x0000000000000001 == 0x0000000000000001
215    }
216
217    /// Bit 1 - reserved
218    pub fn reserved_1(&self) -> bool {
219        self.raw & 0x0000000000000002 == 0x0000000000000002
220    }
221
222    /// Bit 2 - TPM Device Characteristics are not supported.
223    pub fn not_supported(&self) -> bool {
224        self.raw & 0x0000000000000004 == 0x0000000000000004
225    }
226
227    /// Bit 3 - Family configurable via firmware update; for example, switching between TPM 1.2
228    pub fn family_configurable_via_firmware(&self) -> bool {
229        self.raw & 0x0000000000000008 == 0x0000000000000008
230    }
231
232    /// Bit 4 - Family configurable via platform software support, such as BIOS Setup; for example,
233    pub fn family_configurable_via_software(&self) -> bool {
234        self.raw & 0x0000000000000010 == 0x0000000000000010
235    }
236
237    /// Bit 5 - Family configurable via OEM proprietary mechanism; for example, switching between TPM 1.2 and TPM 2.0.
238    pub fn family_configurable_via_oem(&self) -> bool {
239        self.raw & 0x0000000000000020 == 0x0000000000000020
240    }
241}
242
243impl fmt::Debug for TpmDeviceCharacteristics {
244    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
245        fmt.debug_struct(std::any::type_name::<TpmDeviceCharacteristics>())
246            .field("raw", &self.raw)
247            .field("reserved_0", &self.reserved_0())
248            .field("reserved_1", &self.reserved_1())
249            .field("not_supported", &self.not_supported())
250            .field(
251                "family_configurable_via_firmware",
252                &self.family_configurable_via_firmware(),
253            )
254            .field(
255                "family_configurable_via_software",
256                &self.family_configurable_via_software(),
257            )
258            .field(
259                "family_configurable_via_oem",
260                &self.family_configurable_via_oem(),
261            )
262            .finish()
263    }
264}
265
266impl Serialize for TpmDeviceCharacteristics {
267    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
268    where
269        S: Serializer,
270    {
271        let mut state = serializer.serialize_struct("TpmDeviceCharacteristics", 7)?;
272        state.serialize_field("raw", &self.raw)?;
273        state.serialize_field("reserved_0", &self.reserved_0())?;
274        state.serialize_field("reserved_1", &self.reserved_1())?;
275        state.serialize_field("not_supported", &self.not_supported())?;
276        state.serialize_field(
277            "family_configurable_via_firmware",
278            &self.family_configurable_via_firmware(),
279        )?;
280        state.serialize_field(
281            "family_configurable_via_software",
282            &self.family_configurable_via_software(),
283        )?;
284        state.serialize_field(
285            "family_configurable_via_oem",
286            &self.family_configurable_via_oem(),
287        )?;
288        state.end()
289    }
290}
291
292#[cfg(test)]
293mod tests {
294    use super::*;
295
296    #[test]
297    fn unit_test() {
298        let struct_type43 = vec![
299            0x2B, 0x1F, 0x3C, 0x00, 0x00, 0x58, 0x46, 0x49, 0x02, 0x00, 0x3E, 0x00, 0x05, 0x00,
300            0x00, 0x36, 0x0C, 0x00, 0x02, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
301            0x00, 0x00, 0x00, 0x54, 0x50, 0x4D, 0x20, 0x32, 0x2E, 0x30, 0x00, 0x49, 0x4E, 0x46,
302            0x49, 0x4E, 0x45, 0x4F, 0x4E, 0x00, 0x00,
303        ];
304
305        let parts = UndefinedStruct::new(&struct_type43);
306        let test_struct = SMBiosTpmDevice::new(&parts);
307
308        println!("{:?}", test_struct);
309        assert_eq!(
310            test_struct.vendor_id().unwrap().array,
311            &[0, b'X', b'F', b'I']
312        );
313        assert_eq!(test_struct.major_spec_version(), Some(2));
314        assert_eq!(test_struct.minor_spec_version(), Some(0));
315        assert_eq!(test_struct.firmware_version_1(), Some(327742));
316        assert_eq!(test_struct.firmware_version_2(), Some(800256));
317        assert_eq!(
318            test_struct.description().to_string(),
319            "INFINEON".to_string()
320        );
321        assert_eq!(
322            test_struct.characteristics(),
323            Some(TpmDeviceCharacteristics::from(16))
324        );
325        assert_eq!(test_struct.oem_defined(), Some(0));
326    }
327}