use crate::{SMBiosStruct, UndefinedStruct};
use serde::{ser::SerializeStruct, Serialize, Serializer};
use std::{array::TryFromSliceError, convert::TryFrom, fmt, ops::Deref};
pub struct SMBiosTpmDevice<'a> {
parts: &'a UndefinedStruct,
}
impl<'a> SMBiosStruct<'a> for SMBiosTpmDevice<'a> {
const STRUCT_TYPE: u8 = 43u8;
fn new(parts: &'a UndefinedStruct) -> Self {
Self { parts }
}
fn parts(&self) -> &'a UndefinedStruct {
self.parts
}
}
impl<'a> SMBiosTpmDevice<'a> {
pub fn vendor_id(&self) -> Option<VendorId<'_>> {
self.parts
.get_field_data(0x04, 0x08)
.and_then(|array| Some(VendorId::try_from(array).expect("Vendor Id is 4 bytes")))
}
pub fn major_spec_version(&self) -> Option<u8> {
self.parts.get_field_byte(0x08)
}
pub fn minor_spec_version(&self) -> Option<u8> {
self.parts.get_field_byte(0x09)
}
pub fn firmware_version_1(&self) -> Option<u32> {
self.parts.get_field_dword(0x0A)
}
pub fn firmware_version_2(&self) -> Option<u32> {
self.parts.get_field_dword(0x0E)
}
pub fn description(&self) -> Option<String> {
self.parts.get_field_string(0x12)
}
pub fn characteristics(&self) -> Option<TpmDeviceCharacteristics> {
self.parts
.get_field_qword(0x13)
.map(|raw| TpmDeviceCharacteristics::from(raw))
}
pub fn oem_defined(&self) -> Option<u32> {
self.parts.get_field_dword(0x1B)
}
}
impl fmt::Debug for SMBiosTpmDevice<'_> {
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt.debug_struct(std::any::type_name::<SMBiosTpmDevice<'_>>())
.field("header", &self.parts.header)
.field("vendor_id", &self.vendor_id())
.field("major_spec_version", &self.major_spec_version())
.field("minor_spec_version", &self.minor_spec_version())
.field("firmware_version_1", &self.firmware_version_1())
.field("firmware_version_2", &self.firmware_version_2())
.field("description", &self.description())
.field("characteristics", &self.characteristics())
.field("oem_defined", &self.oem_defined())
.finish()
}
}
impl Serialize for SMBiosTpmDevice<'_> {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
let mut state = serializer.serialize_struct("SMBiosTpmDevice", 9)?;
state.serialize_field("header", &self.parts.header)?;
state.serialize_field("vendor_id", &self.vendor_id())?;
state.serialize_field("major_spec_version", &self.major_spec_version())?;
state.serialize_field("minor_spec_version", &self.minor_spec_version())?;
state.serialize_field("firmware_version_1", &self.firmware_version_1())?;
state.serialize_field("firmware_version_2", &self.firmware_version_2())?;
state.serialize_field("description", &self.description())?;
state.serialize_field("characteristics", &self.characteristics())?;
state.serialize_field("oem_defined", &self.oem_defined())?;
state.end()
}
}
#[derive(PartialEq, Eq)]
pub struct VendorId<'a> {
pub array: &'a [u8; 4],
}
impl<'a> TryFrom<&'a [u8]> for VendorId<'a> {
type Error = TryFromSliceError;
fn try_from(raw: &'a [u8]) -> Result<Self, Self::Error> {
<&[u8; 4]>::try_from(raw).and_then(|array| Ok(VendorId { array }))
}
}
impl<'a> fmt::Debug for VendorId<'a> {
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt.debug_struct(std::any::type_name::<VendorId<'_>>())
.field("array", &self.array)
.field("string", &String::from_utf8_lossy(self.array))
.finish()
}
}
impl<'a> Serialize for VendorId<'a> {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
let mut state = serializer.serialize_struct("VendorId", 2)?;
state.serialize_field("array", &self.array)?;
state.serialize_field("string", &String::from_utf8_lossy(self.array))?;
state.end()
}
}
#[derive(PartialEq, Eq)]
pub struct TpmDeviceCharacteristics {
raw: u64,
}
impl Deref for TpmDeviceCharacteristics {
type Target = u64;
fn deref(&self) -> &Self::Target {
&self.raw
}
}
impl From<u64> for TpmDeviceCharacteristics {
fn from(raw: u64) -> Self {
TpmDeviceCharacteristics { raw }
}
}
impl TpmDeviceCharacteristics {
pub fn reserved_0(&self) -> bool {
self.raw & 0x0000000000000001 == 0x0000000000000001
}
pub fn reserved_1(&self) -> bool {
self.raw & 0x0000000000000002 == 0x0000000000000002
}
pub fn not_supported(&self) -> bool {
self.raw & 0x0000000000000004 == 0x0000000000000004
}
pub fn family_configurable_via_firmware(&self) -> bool {
self.raw & 0x0000000000000008 == 0x0000000000000008
}
pub fn family_configurable_via_software(&self) -> bool {
self.raw & 0x0000000000000010 == 0x0000000000000010
}
pub fn family_configurable_via_oem(&self) -> bool {
self.raw & 0x0000000000000020 == 0x0000000000000020
}
}
impl fmt::Debug for TpmDeviceCharacteristics {
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt.debug_struct(std::any::type_name::<TpmDeviceCharacteristics>())
.field("raw", &self.raw)
.field("reserved_0", &self.reserved_0())
.field("reserved_1", &self.reserved_1())
.field("not_supported", &self.not_supported())
.field(
"family_configurable_via_firmware",
&self.family_configurable_via_firmware(),
)
.field(
"family_configurable_via_software",
&self.family_configurable_via_software(),
)
.field(
"family_configurable_via_oem",
&self.family_configurable_via_oem(),
)
.finish()
}
}
impl Serialize for TpmDeviceCharacteristics {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
let mut state = serializer.serialize_struct("TpmDeviceCharacteristics", 7)?;
state.serialize_field("raw", &self.raw)?;
state.serialize_field("reserved_0", &self.reserved_0())?;
state.serialize_field("reserved_1", &self.reserved_1())?;
state.serialize_field("not_supported", &self.not_supported())?;
state.serialize_field(
"family_configurable_via_firmware",
&self.family_configurable_via_firmware(),
)?;
state.serialize_field(
"family_configurable_via_software",
&self.family_configurable_via_software(),
)?;
state.serialize_field(
"family_configurable_via_oem",
&self.family_configurable_via_oem(),
)?;
state.end()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn unit_test() {
let struct_type43 = vec![
0x2B, 0x1F, 0x3C, 0x00, 0x00, 0x58, 0x46, 0x49, 0x02, 0x00, 0x3E, 0x00, 0x05, 0x00,
0x00, 0x36, 0x0C, 0x00, 0x02, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x54, 0x50, 0x4D, 0x20, 0x32, 0x2E, 0x30, 0x00, 0x49, 0x4E, 0x46,
0x49, 0x4E, 0x45, 0x4F, 0x4E, 0x00, 0x00,
];
let parts = UndefinedStruct::new(&struct_type43);
let test_struct = SMBiosTpmDevice::new(&parts);
println!("{:?}", test_struct);
assert_eq!(
test_struct.vendor_id().unwrap().array,
&[0, b'X', b'F', b'I']
);
assert_eq!(test_struct.major_spec_version(), Some(2));
assert_eq!(test_struct.minor_spec_version(), Some(0));
assert_eq!(test_struct.firmware_version_1(), Some(327742));
assert_eq!(test_struct.firmware_version_2(), Some(800256));
assert_eq!(test_struct.description(), Some("INFINEON".to_string()));
assert_eq!(
test_struct.characteristics(),
Some(TpmDeviceCharacteristics::from(16))
);
assert_eq!(test_struct.oem_defined(), Some(0));
}
}