Add TrustedModuleRequiredToBoot setter function

TrustedModuleRequiredToBoot is a Redfish ComputerSystem v1_14_0
property, determining if a working TPM is required in order to boot
the host. The TPM Required property is mapped to the "TPMEnable" D-Bus
property. The possible values for the Redfish property are "Required"
and "Disabled".

This commit will add the PATCH operations to the
TrustedModuleRequiredToBoot Redfish property.
(See https://gerrit.openbmc-project.xyz/c/openbmc/bmcweb/+/43930
for the GET operations for this property).

Testing:

1) Curl Testing: I manually tested retrieving the property:
*Default value of TrustedModuleRequiredToBoot is ??Required??

curl -k -H "X-Auth-Token: $token" -X PATCH -d \
'{"TrustedModuleRequiredToBoot":false}' \
https://${bmc}/redfish/v1/Systems/system

curl -k -H "X-Auth-Token: $token" \
https://${bmc}/redfish/v1/Systems/system
{
  "@odata.id": "/redfish/v1/Systems/system",
  "@odata.type": "#ComputerSystem.v1_14_0.ComputerSystem",
...
  "Boot": {
    "AutomaticRetryAttempts": 3,
    ??
    "RemainingAutomaticRetryAttempts": 3,
    "TrustedModuleRequiredToBoot": "Disabled"
  },
...

On HW: D-Bus TPMEnable shows up correctly as 'false'
'# busctl get-property xyz.openbmc_project.Settings \
/xyz/openbmc_project/control/host0/TPMEnable \
xyz.openbmc_project.Control.TPM.Policy TPMEnable'
b false

2) Redfish Validator Testing: Tested on ComputerSystem v1_14_0 schema
    Validator Test everything passed and 0 failures.

Signed-off-by: Ali Ahmed <ama213000@gmail.com>
Change-Id: Ie96a6afca179e45bef35813a3fa9c8a10cdf234e
diff --git a/redfish-core/lib/systems.hpp b/redfish-core/lib/systems.hpp
index fc6e2c7..320f4e4 100644
--- a/redfish-core/lib/systems.hpp
+++ b/redfish-core/lib/systems.hpp
@@ -1476,6 +1476,94 @@
 }
 
 /**
+ * @brief Set TrustedModuleRequiredToBoot property. Determines whether or not
+ * TPM is required for booting the host.
+ *
+ * @param[in] aResp         Shared pointer for generating response message.
+ * @param[in] tpmRequired   Value to set TPM Required To Boot property to.
+ *
+ * @return None.
+ */
+inline void setTrustedModuleRequiredToBoot(
+    const std::shared_ptr<bmcweb::AsyncResp>& aResp, const bool tpmRequired)
+{
+    BMCWEB_LOG_DEBUG << "Set TrustedModuleRequiredToBoot.";
+
+    crow::connections::systemBus->async_method_call(
+        [aResp, tpmRequired](
+            const boost::system::error_code ec,
+            std::vector<std::pair<
+                std::string,
+                std::vector<std::pair<std::string, std::vector<std::string>>>>>&
+                subtree) {
+            if (ec)
+            {
+                BMCWEB_LOG_DEBUG
+                    << "DBUS response error on TPM.Policy GetSubTree" << ec;
+                messages::internalError(aResp->res);
+                return;
+            }
+            if (subtree.size() == 0)
+            {
+                messages::propertyValueNotInList(aResp->res, "ComputerSystem",
+                                                 "TrustedModuleRequiredToBoot");
+                return;
+            }
+
+            /* When there is more than one TPMEnable object... */
+            if (subtree.size() > 1)
+            {
+                BMCWEB_LOG_DEBUG
+                    << "DBUS response has more than 1 TPM Enable object:"
+                    << subtree.size();
+                // Throw an internal Error and return
+                messages::internalError(aResp->res);
+                return;
+            }
+
+            // Make sure the Dbus response map has a service and objectPath
+            // field
+            if (subtree[0].first.empty() || subtree[0].second.size() != 1)
+            {
+                BMCWEB_LOG_DEBUG << "TPM.Policy mapper error!";
+                messages::internalError(aResp->res);
+                return;
+            }
+
+            const std::string& path = subtree[0].first;
+            const std::string& serv = subtree[0].second.begin()->first;
+
+            if (serv.empty())
+            {
+                BMCWEB_LOG_DEBUG << "TPM.Policy service mapper error!";
+                messages::internalError(aResp->res);
+                return;
+            }
+
+            // Valid TPM Enable object found, now setting the value
+            crow::connections::systemBus->async_method_call(
+                [aResp](const boost::system::error_code ec) {
+                    if (ec)
+                    {
+                        BMCWEB_LOG_DEBUG << "DBUS response error: Set "
+                                            "TrustedModuleRequiredToBoot"
+                                         << ec;
+                        messages::internalError(aResp->res);
+                        return;
+                    }
+                    BMCWEB_LOG_DEBUG << "Set TrustedModuleRequiredToBoot done.";
+                },
+                serv, path, "org.freedesktop.DBus.Properties", "Set",
+                "xyz.openbmc_project.Control.TPM.Policy", "TPMEnable",
+                std::variant<bool>(tpmRequired));
+        },
+        "xyz.openbmc_project.ObjectMapper",
+        "/xyz/openbmc_project/object_mapper",
+        "xyz.openbmc_project.ObjectMapper", "GetSubTree", "/", int32_t(0),
+        std::array<const char*, 1>{"xyz.openbmc_project.Control.TPM.Policy"});
+}
+
+/**
  * @brief Sets boot properties into DBUS object(s).
  *
  * @param[in] aResp           Shared pointer for generating response message.
@@ -2758,13 +2846,15 @@
                 std::optional<std::string> assetTag;
                 std::optional<std::string> powerRestorePolicy;
                 std::optional<std::string> powerMode;
-
+                std::optional<bool> trustedModuleRequiredToBoot;
                 if (!json_util::readJson(
                         req, asyncResp->res, "IndicatorLED", indicatorLed,
                         "LocationIndicatorActive", locationIndicatorActive,
                         "Boot", bootProps, "WatchdogTimer", wdtTimerProps,
                         "PowerRestorePolicy", powerRestorePolicy, "AssetTag",
-                        assetTag, "PowerMode", powerMode))
+                        assetTag, "PowerMode", powerMode,
+                        "TrustedModuleRequiredToBoot",
+                        trustedModuleRequiredToBoot))
                 {
                     return;
                 }
@@ -2844,6 +2934,12 @@
                 {
                     setPowerMode(asyncResp, *powerMode);
                 }
+
+                if (trustedModuleRequiredToBoot)
+                {
+                    setTrustedModuleRequiredToBoot(
+                        asyncResp, *trustedModuleRequiredToBoot);
+                }
             });
 }