smbios-mdr: Add TPM Device Information
Type 43 of SMBIOS records defines the data structure to expose
TPM Device information. Add patch which displays the TPM Device
information on dbus.
Introduced `TPM_DBUS` meson option which will be disabled by default
When enabled, the TPM information is populated on DBUS.
Tested:
TPM information is available under dbus tree of smbios-mdr
```
:~# busctl tree xyz.openbmc_project.Smbios.MDR_V2
`- /xyz
`- /xyz/openbmc_project
|- /xyz/openbmc_project/Smbios
| `- /xyz/openbmc_project/Smbios/MDR_V2
|- /xyz/openbmc_project/inventory
| `- /xyz/openbmc_project/inventory/system
| `- /xyz/openbmc_project/inventory/system/chassis
| |- /xyz/openbmc_project/inventory/system/chassis/motherboard/bios
| `- /xyz/openbmc_project/inventory/system/chassis/motherboard/tpm
```
Change-Id: Icd42f4f043bf5a970f4829e5d318568360fe4b59
Signed-off-by: Prithvi Pai <ppai@nvidia.com>
diff --git a/include/mdrv2.hpp b/include/mdrv2.hpp
index d248073..2459a89 100644
--- a/include/mdrv2.hpp
+++ b/include/mdrv2.hpp
@@ -20,6 +20,7 @@
#include "pcieslot.hpp"
#include "smbios_mdrv2.hpp"
#include "system.hpp"
+#include "tpm.hpp"
#include <sys/stat.h>
#include <sys/types.h>
@@ -188,9 +189,11 @@
std::optional<size_t> getTotalCpuSlot(void);
std::optional<size_t> getTotalDimmSlot(void);
std::optional<size_t> getTotalPcieSlot(void);
+ std::optional<size_t> getTotalTpm(void);
std::vector<std::unique_ptr<Cpu>> cpus;
std::vector<std::unique_ptr<Dimm>> dimms;
std::vector<std::unique_ptr<Pcie>> pcies;
+ std::vector<std::unique_ptr<Tpm>> tpms;
std::unique_ptr<System> system;
std::shared_ptr<sdbusplus::asio::dbus_interface> smbiosInterface;
diff --git a/include/smbios_mdrv2.hpp b/include/smbios_mdrv2.hpp
index 59680bf..2be6dad 100644
--- a/include/smbios_mdrv2.hpp
+++ b/include/smbios_mdrv2.hpp
@@ -165,6 +165,8 @@
static constexpr const char* systemSuffix = "/chassis/motherboard/bios";
+static constexpr const char* tpmSuffix = "/chassis/motherboard/tpm";
+
constexpr std::array<SMBIOSVersion, 8> supportedSMBIOSVersions{
SMBIOSVersion{3, 0}, SMBIOSVersion{3, 2}, SMBIOSVersion{3, 3},
SMBIOSVersion{3, 4}, SMBIOSVersion{3, 5}, SMBIOSVersion{3, 6},
@@ -190,6 +192,7 @@
systemEventLogType = 15,
physicalMemoryArrayType = 16,
memoryDeviceType = 17,
+ tpmDeviceType = 43,
} SmbiosType;
static constexpr uint8_t separateLen = 2;
diff --git a/include/tpm.hpp b/include/tpm.hpp
new file mode 100644
index 0000000..efa14f0
--- /dev/null
+++ b/include/tpm.hpp
@@ -0,0 +1,95 @@
+#pragma once
+#include "smbios_mdrv2.hpp"
+
+#include <sdbusplus/asio/connection.hpp>
+#include <xyz/openbmc_project/Association/Definitions/server.hpp>
+#include <xyz/openbmc_project/Inventory/Decorator/Asset/server.hpp>
+#include <xyz/openbmc_project/Inventory/Item/Tpm/server.hpp>
+#include <xyz/openbmc_project/Inventory/Item/server.hpp>
+#include <xyz/openbmc_project/Software/Version/server.hpp>
+
+namespace phosphor
+{
+
+namespace smbios
+{
+
+using tpm = sdbusplus::server::xyz::openbmc_project::inventory::item::Tpm;
+using asset =
+ sdbusplus::server::xyz::openbmc_project::inventory::decorator::Asset;
+using Item = sdbusplus::server::xyz::openbmc_project::inventory::Item;
+using softwareversion =
+ sdbusplus::server::xyz::openbmc_project::software::Version;
+using association =
+ sdbusplus::server::xyz::openbmc_project::association::Definitions;
+
+constexpr uint8_t tpmMajorVerion1 = 0x01;
+constexpr uint8_t tpmMajorVerion2 = 0x02;
+
+class Tpm :
+ sdbusplus::server::object_t<tpm, asset, Item, association, softwareversion>
+{
+ public:
+ Tpm() = delete;
+ ~Tpm() = default;
+ Tpm(const Tpm&) = delete;
+ Tpm& operator=(const Tpm&) = delete;
+ Tpm(Tpm&&) = default;
+ Tpm& operator=(Tpm&&) = default;
+
+ Tpm(sdbusplus::bus_t& bus, const std::string& objPath, const uint8_t tpmID,
+ uint8_t* smbiosTableStorage, const std::string& motherboard) :
+ sdbusplus::server::object_t<tpm, asset, Item, association,
+ softwareversion>(bus, objPath.c_str()),
+ tpmId(tpmID), storage(smbiosTableStorage), motherboardPath(motherboard)
+ {
+ tpmInfoUpdate(smbiosTableStorage, motherboard);
+ }
+
+ void tpmInfoUpdate(uint8_t* smbiosTableStorage,
+ const std::string& motherboard);
+
+ private:
+ uint8_t tpmId;
+
+ uint8_t* storage;
+
+ std::string motherboardPath;
+ struct TPMInfo
+ {
+ uint8_t type;
+ uint8_t length;
+ uint16_t handle;
+ char vendor[4];
+ uint8_t specMajor;
+ uint8_t specMinor;
+ uint32_t firmwareVersion1;
+ uint32_t firmwareVersion2;
+ uint8_t description;
+ uint64_t characteristics;
+ uint32_t oem;
+ } __attribute__((packed));
+
+ struct TPMVersionSpec1
+ {
+ uint8_t specMajor;
+ uint8_t specMinor;
+ uint8_t revMajor;
+ uint8_t revMinor;
+ } __attribute__((packed));
+
+ struct TPMVersionSpec2
+ {
+ uint16_t revMinor;
+ uint16_t revMajor;
+ } __attribute__((packed));
+
+ void tpmVendor(const struct TPMInfo* tpmInfo);
+ void tpmFirmwareVersion(const struct TPMInfo* tpmInfo);
+ void tpmDescription(const uint8_t positionNum, const uint8_t structLen,
+ uint8_t* dataIn);
+};
+
+} // namespace smbios
+
+} // namespace phosphor
diff --git a/meson.options b/meson.options
index 23e4ed1..f93f1ea 100644
--- a/meson.options
+++ b/meson.options
@@ -48,3 +48,10 @@
value: 'enabled',
description: 'Build IPMI blob library for SMBIOS transfer',
)
+
+option(
+ 'tpm-dbus',
+ type: 'feature',
+ value: 'disabled',
+ description: 'Expose TPM D-Bus Interface',
+)
diff --git a/src/mdrv2.cpp b/src/mdrv2.cpp
index 25ef98a..f33fbc1 100644
--- a/src/mdrv2.cpp
+++ b/src/mdrv2.cpp
@@ -619,6 +619,38 @@
}
}
+#ifdef TPM_DBUS
+
+ num = getTotalTpm();
+ if (!num)
+ {
+ phosphor::logging::log<phosphor::logging::level::ERR>("get tpm failed");
+ return;
+ }
+ // In case the new size is smaller than old, trim the vector
+ if (*num < tpms.size())
+ {
+ tpms.resize(*num);
+ }
+
+ for (unsigned int index = 0; index < *num; index++)
+ {
+ std::string path =
+ smbiosInventoryPath + tpmSuffix + std::to_string(index);
+ if (index + 1 > tpms.size())
+ {
+ tpms.emplace_back(std::make_unique<phosphor::smbios::Tpm>(
+ *bus, path, index, smbiosDir.dir[smbiosDirIndex].dataStorage,
+ motherboardPath));
+ }
+ else
+ {
+ tpms[index]->tpmInfoUpdate(
+ smbiosDir.dir[smbiosDirIndex].dataStorage, motherboardPath);
+ }
+ }
+#endif
+
system.reset();
system = std::make_unique<System>(bus, smbiosInventoryPath + systemSuffix,
smbiosDir.dir[smbiosDirIndex].dataStorage,
@@ -734,6 +766,40 @@
return num;
}
+std::optional<size_t> MDRV2::getTotalTpm()
+{
+ uint8_t* dataIn = smbiosDir.dir[smbiosDirIndex].dataStorage;
+ size_t num = 0;
+
+ if (dataIn == nullptr)
+ {
+ phosphor::logging::log<phosphor::logging::level::ERR>(
+ "Fail to get tpm total slot - no storage data");
+ return std::nullopt;
+ }
+
+ while (1)
+ {
+ dataIn = getSMBIOSTypePtr(dataIn, tpmDeviceType);
+ if (dataIn == nullptr)
+ {
+ break;
+ }
+ num++;
+ dataIn = smbiosNextPtr(dataIn);
+ if (dataIn == nullptr)
+ {
+ break;
+ }
+ if (num >= limitEntryLen)
+ {
+ break;
+ }
+ }
+
+ return num;
+}
+
bool MDRV2::checkSMBIOSVersion(uint8_t* dataIn)
{
const std::string anchorString21 = "_SM_";
diff --git a/src/meson.build b/src/meson.build
index 1c983bd..3a2bc17 100644
--- a/src/meson.build
+++ b/src/meson.build
@@ -15,6 +15,10 @@
cpp_args_smbios += ['-DSLOT_DRIVE_PRESENCE']
endif
+if get_option('tpm-dbus').allowed()
+ cpp_args_smbios += ['-DTPM_DBUS']
+endif
+
executable(
'smbiosmdrv2app',
'mdrv2.cpp',
@@ -23,6 +27,7 @@
'dimm.cpp',
'system.cpp',
'pcieslot.cpp',
+ 'tpm.cpp',
cpp_args: cpp_args_smbios,
dependencies: [
boost_dep,
diff --git a/src/tpm.cpp b/src/tpm.cpp
new file mode 100644
index 0000000..74279d0
--- /dev/null
+++ b/src/tpm.cpp
@@ -0,0 +1,102 @@
+#include "tpm.hpp"
+
+#include "mdrv2.hpp"
+
+#include <fstream>
+#include <iomanip>
+#include <iostream>
+#include <sstream>
+
+namespace phosphor
+{
+namespace smbios
+{
+
+void Tpm::tpmInfoUpdate(uint8_t* smbiosTableStorage,
+ const std::string& motherboard)
+{
+ storage = smbiosTableStorage;
+ motherboardPath = motherboard;
+
+ uint8_t* dataIn = storage;
+ dataIn = getSMBIOSTypePtr(dataIn, tpmDeviceType);
+ if (dataIn == nullptr)
+ {
+ return;
+ }
+ for (uint8_t index = 0; index < tpmId; index++)
+ {
+ dataIn = smbiosNextPtr(dataIn);
+ if (dataIn == nullptr)
+ {
+ return;
+ }
+ dataIn = getSMBIOSTypePtr(dataIn, tpmDeviceType);
+ if (dataIn == nullptr)
+ {
+ return;
+ }
+ }
+ auto tpmInfo = reinterpret_cast<struct TPMInfo*>(dataIn);
+
+ present(true);
+ purpose(softwareversion::VersionPurpose::Other);
+ tpmVendor(tpmInfo);
+ tpmFirmwareVersion(tpmInfo);
+ tpmDescription(tpmInfo->description, tpmInfo->length, dataIn);
+ if (!motherboardPath.empty())
+ {
+ std::vector<std::tuple<std::string, std::string, std::string>> assocs;
+ assocs.emplace_back("chassis", "trusted_components", motherboardPath);
+ association::associations(assocs);
+ }
+}
+
+void Tpm::tpmVendor(const struct TPMInfo* tpmInfo)
+{
+ constexpr int vendorIdLength = 4;
+ // Specified as four ASCII characters, as defined by TCG Vendor ID
+ char vendorId[vendorIdLength + 1];
+ int i;
+ for (i = 0; i < vendorIdLength && tpmInfo->vendor[i] != '\0'; i++)
+ {
+ if (std::isprint(tpmInfo->vendor[i]))
+ {
+ vendorId[i] = tpmInfo->vendor[i];
+ }
+ else
+ {
+ vendorId[i] = '.';
+ }
+ }
+ vendorId[i] = '\0';
+ manufacturer(vendorId);
+}
+
+void Tpm::tpmFirmwareVersion(const struct TPMInfo* tpmInfo)
+{
+ std::stringstream stream;
+
+ if (tpmInfo->specMajor == tpmMajorVerion1)
+ {
+ auto ver = reinterpret_cast<const struct TPMVersionSpec1*>(
+ &tpmInfo->firmwareVersion1);
+ stream << ver->revMajor << "." << ver->revMinor;
+ }
+ else if (tpmInfo->specMajor == tpmMajorVerion2)
+ {
+ auto ver = reinterpret_cast<const struct TPMVersionSpec2*>(
+ &tpmInfo->firmwareVersion1);
+ stream << ver->revMajor << "." << ver->revMinor;
+ }
+ version(stream.str());
+}
+
+void Tpm::tpmDescription(const uint8_t positionNum, const uint8_t structLen,
+ uint8_t* dataIn)
+{
+ std::string result = positionToString(positionNum, structLen, dataIn);
+ prettyName(result);
+}
+} // namespace smbios
+} // namespace phosphor