TPM code updater

This commit introduces a TPM code updater that currently supports
reading the firmware version for both Infineon and Nuvoton TPM 2.0.
Support for firmware updates will be introduced in a future patch.

The updater's configuration are managed by the EM [1].
[1] https://gerrit.openbmc.org/c/openbmc/entity-manager/+/82416

Tested on Yosemite5 with the following steps:

1. Display the fw inventory:
```
curl --silent $creds https://$bmc/redfish/v1/UpdateService/FirmwareInventory
{
  "@odata.id": "/redfish/v1/UpdateService/FirmwareInventory",
  "@odata.type": "#SoftwareInventoryCollection.SoftwareInventoryCollection",
  "Members": [
    {...},
    {
      "@odata.id": "/redfish/v1/UpdateService/FirmwareInventory/Yosemite5_TPM_4945"
    },
    {...}
  ],
  "Members@odata.count": 4,
  "Name": "Software Inventory Collection"
}
```

2. Query TPM version:
```
curl --silent $creds https://$bmc/redfish/v1/UpdateService/FirmwareInventory/Yosemite5_TPM_4945
{
  "@odata.id": "/redfish/v1/UpdateService/FirmwareInventory/Yosemite5_TPM_4945",
  "@odata.type": "#SoftwareInventory.v1_1_0.SoftwareInventory",
  "Description": "Unknown image",
  "Id": "Yosemite5_TPM_4945",
  "Name": "Software Inventory",
  "Status": {
    "Health": "Warning",
    "HealthRollup": "OK",
    "State": "Disabled"
  },
  "Updateable": false,
  "Version": "15.23"
}
```

Change-Id: I42568242356d55fe005ba1f41ddf8aaf9f682fc8
Signed-off-by: Kevin Tung <kevin.tung.openbmc@gmail.com>
diff --git a/tpm/tpm_software_manager.cpp b/tpm/tpm_software_manager.cpp
new file mode 100644
index 0000000..227cd84
--- /dev/null
+++ b/tpm/tpm_software_manager.cpp
@@ -0,0 +1,87 @@
+#include "tpm_software_manager.hpp"
+
+#include "common/include/dbus_helper.hpp"
+#include "tpm_device.hpp"
+
+#include <phosphor-logging/lg2.hpp>
+
+PHOSPHOR_LOG2_USING;
+
+namespace SoftwareInf = phosphor::software;
+
+void TPMSoftwareManager::start()
+{
+    std::vector<std::string> configIntfs = {
+        "xyz.openbmc_project.Configuration.TPM2Firmware",
+    };
+
+    ctx.spawn(initDevices(configIntfs));
+    ctx.run();
+}
+
+sdbusplus::async::task<bool> TPMSoftwareManager::initDevice(
+    const std::string& service, const std::string& path, SoftwareConfig& config)
+{
+    const std::string configIface =
+        "xyz.openbmc_project.Configuration." + config.configType;
+
+    std::optional<uint8_t> tpmIndex = co_await dbusGetRequiredProperty<uint8_t>(
+        ctx, service, path, configIface, "TPMIndex");
+
+    if (!tpmIndex.has_value())
+    {
+        error("Missing property: TPMIndex");
+        co_return false;
+    }
+
+    std::optional<std::string> type =
+        co_await dbusGetRequiredProperty<std::string>(ctx, service, path,
+                                                      configIface, "Type");
+    if (!type.has_value())
+    {
+        error("Missing property: Type");
+        co_return false;
+    }
+
+    TPMType tpmType;
+    if (!stringToTPMType(type.value(), tpmType))
+    {
+        error("Invalid TPM type: {TYPE}", "TYPE", type.value());
+        co_return false;
+    }
+
+    debug("TPM device: TPM Index={INDEX}, Type={TYPE}", "INDEX",
+          tpmIndex.value(), "TYPE", type.value());
+
+    auto tpmDevice = std::make_unique<TPMDevice>(ctx, tpmType, tpmIndex.value(),
+                                                 config, this);
+
+    std::unique_ptr<SoftwareInf::Software> software =
+        std::make_unique<SoftwareInf::Software>(ctx, *tpmDevice);
+
+    software->setVersion(co_await tpmDevice->getVersion());
+
+    if (tpmDevice->isUpdateSupported())
+    {
+        std::set<RequestedApplyTimes> allowedApplyTimes = {
+            RequestedApplyTimes::OnReset};
+
+        software->enableUpdate(allowedApplyTimes);
+    }
+
+    tpmDevice->softwareCurrent = std::move(software);
+
+    devices.insert({config.objectPath, std::move(tpmDevice)});
+
+    co_return true;
+}
+
+int main()
+{
+    sdbusplus::async::context ctx;
+
+    TPMSoftwareManager tpmSoftwareManager(ctx);
+
+    tpmSoftwareManager.start();
+    return 0;
+}