PEL: Added phal specific service action support

This commits enables the basic infrastructure to add service
actions(guard/deconfigure) supports for "phal"  feature enabled
systems. Also enabled "guard" related service , which includes
creating guard D-Bus object using hardware isolation D-Bus api's

To enable this support, PEL users has to include the array of
JSON callouts, which includes the below required informations.
"EntityPath": entity path of the hardware from the PHAL device tree.
"GuardType":  Guard type string defined libekb_p10.
"Guarded": boolean, true to create guard records.

Tested: created guard records and verified
root@xxxx:~# guard -l
ID       | ERROR    |  Type  | Path
00000001 | 50000684 | fatal | physical:sys-0/node-0/proc-0
00000002 | 50000685 | fatal | physical:sys-0/node-0/proc-1
00000003 | 50000686 | fatal | physical:sys-0/node-0/proc-2
00000004 | 50000687 | fatal | physical:sys-0/node-0/proc-3

Signed-off-by: Jayanth Othayoth <ojayanth@in.ibm.com>
Change-Id: Ibc57ae0363cd5fb9facd2ed7049a70806a5b891e
diff --git a/extensions/openpower-pels/meson.build b/extensions/openpower-pels/meson.build
index b78ccf0..4659945 100644
--- a/extensions/openpower-pels/meson.build
+++ b/extensions/openpower-pels/meson.build
@@ -39,6 +39,7 @@
     extra_sources += [
         'sbe_ffdc_handler.cpp',
         'fapi_data_process.cpp',
+        'phal_service_actions.cpp',
     ]
     extra_dependencies += [
         dependency('libdt-api'),
diff --git a/extensions/openpower-pels/pel.cpp b/extensions/openpower-pels/pel.cpp
index 8f397cd..30fbf51 100644
--- a/extensions/openpower-pels/pel.cpp
+++ b/extensions/openpower-pels/pel.cpp
@@ -13,6 +13,8 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+#include "config.h"
+
 #include "pel.hpp"
 
 #include "bcd_time.hpp"
@@ -29,6 +31,7 @@
 #include "user_data_formats.hpp"
 
 #ifdef PEL_ENABLE_PHAL
+#include "phal_service_actions.hpp"
 #include "sbe_ffdc_handler.hpp"
 #endif
 
@@ -154,6 +157,11 @@
         addUserDataSection(std::move(ud));
     }
 
+#ifdef PEL_ENABLE_PHAL
+    auto path = std::string(OBJ_ENTRY) + '/' + std::to_string(obmcLogID);
+    openpower::pels::phal::createServiceActions(callouts, path, dataIface);
+#endif
+
     // Store in the PEL any important debug data created while
     // building the PEL sections.
     if (!debugData.empty())
diff --git a/extensions/openpower-pels/phal_service_actions.cpp b/extensions/openpower-pels/phal_service_actions.cpp
new file mode 100644
index 0000000..a534ddf
--- /dev/null
+++ b/extensions/openpower-pels/phal_service_actions.cpp
@@ -0,0 +1,151 @@
+#include "phal_service_actions.hpp"
+
+#include <attributes_info.H>
+#include <fmt/format.h>
+
+#include <phosphor-logging/log.hpp>
+
+namespace openpower
+{
+namespace pels
+{
+namespace phal
+{
+using namespace phosphor::logging;
+
+/**
+ * @brief Helper function to get EntrySeverity based on
+ *        the given GardType
+ *
+ * @param[in] guardType openpower gard type
+ *
+ * @return EntrySeverity on success
+ *         Empty optional on failure
+ */
+std::optional<EntrySeverity> getEntrySeverityType(const std::string& guardType)
+{
+    if ((guardType == "GARD_Unrecoverable") || (guardType == "GARD_Fatal"))
+    {
+        return EntrySeverity::Critical;
+    }
+    else if (guardType == "GARD_User_Manual")
+    {
+        return EntrySeverity::Manual;
+    }
+    else if (guardType == "GARD_Predictive")
+    {
+        return EntrySeverity::Warning;
+    }
+    else
+    {
+        log<level::ERR>(
+            fmt::format("GUARD: Unsupported GardType [{}] was given ",
+                        "to get the hardware isolation entry severity type",
+                        guardType.c_str())
+                .c_str());
+    }
+    return std::nullopt;
+}
+
+/**
+ * @brief Helper function to create guard records.
+ *
+ * User need to fill the JSON callouts array with below keywords/data
+ * "Entitypath": entity path of the hardware from the PHAL device tree.
+ * "Guardtype": The hardware isolation severity which is defined in
+ *              xyz.openbmc_project.HardwareIsolation.Entry
+ * "Guarded": boolean, true to create gurad records.
+ *
+ * @param[in] jsonCallouts - The array of JSON callouts, or an empty object.
+ * @param[in] path - The BMC error log object path
+ * @param[in] dataIface - The DataInterface object
+ */
+void createGuardRecords(const nlohmann::json& jsonCallouts,
+                        const std::string& path,
+                        const DataInterfaceBase& dataIface)
+{
+    if (jsonCallouts.empty())
+    {
+        return;
+    }
+
+    if (!jsonCallouts.is_array())
+    {
+        log<level::ERR>("GUARD: Callout JSON isn't an array");
+        return;
+    }
+    for (const auto& _callout : jsonCallouts)
+    {
+        try
+        {
+            // Check Callout data conatains Guarded requests.
+            if (!_callout.contains("Guarded"))
+            {
+                continue;
+            }
+            if (!_callout.at("Guarded").get<bool>())
+            {
+                continue;
+            }
+            // Get Entity path required for guard D-bus method
+            // "CreateWithEntityPath"
+            if (!_callout.contains("EntityPath"))
+            {
+                log<level::ERR>(
+                    "GUARD: Callout data, missing EntityPath information");
+                continue;
+            }
+            using EntityPath = std::vector<uint8_t>;
+
+            auto entityPath = _callout.at("EntityPath").get<EntityPath>();
+
+            std::stringstream ss;
+            for (uint32_t a = 0; a < sizeof(ATTR_PHYS_BIN_PATH_Type); a++)
+            {
+                ss << " 0x" << std::hex << static_cast<int>(entityPath[a]);
+            }
+            std::string s = ss.str();
+            log<level::INFO>(fmt::format("GUARD :({})", s).c_str());
+
+            // Get Guard type
+            auto severity = EntrySeverity::Warning;
+            if (!_callout.contains("GuardType"))
+            {
+                log<level::ERR>(
+                    "GUARD: doesn't have Severity, setting to warning");
+            }
+            else
+            {
+                auto guardType = _callout.at("GuardType").get<std::string>();
+                // convert GuardType to severity type.
+                auto sType = getEntrySeverityType(guardType);
+                if (sType.has_value())
+                {
+                    severity = sType.value();
+                }
+            }
+            // Create guard record
+            auto type = sdbusplus::xyz::openbmc_project::HardwareIsolation::
+                server::convertForMessage(severity);
+            dataIface.createGuardRecord(entityPath, type, path);
+        }
+        catch (const std::exception& e)
+        {
+            log<level::INFO>(
+                fmt::format("GUARD: Failed entry creation exception:({})",
+                            e.what())
+                    .c_str());
+        }
+    }
+}
+
+void createServiceActions(const nlohmann::json& jsonCallouts,
+                          const std::string& path,
+                          const DataInterfaceBase& dataIface)
+{
+    // Create Guard records.
+    createGuardRecords(jsonCallouts, path, dataIface);
+}
+} // namespace phal
+} // namespace pels
+} // namespace openpower
diff --git a/extensions/openpower-pels/phal_service_actions.hpp b/extensions/openpower-pels/phal_service_actions.hpp
new file mode 100644
index 0000000..84a700e
--- /dev/null
+++ b/extensions/openpower-pels/phal_service_actions.hpp
@@ -0,0 +1,30 @@
+#pragma once
+
+#include "data_interface.hpp"
+
+#include <nlohmann/json.hpp>
+#include <xyz/openbmc_project/HardwareIsolation/Entry/server.hpp>
+
+namespace openpower
+{
+namespace pels
+{
+namespace phal
+{
+
+using EntrySeverity =
+    sdbusplus::xyz::openbmc_project::HardwareIsolation::server::Entry::Type;
+
+/**
+ * @brief Helper function to create service actions in the PEL
+ *
+ * @param[in] jsonCallouts - The array of JSON callouts, or an empty object.
+ * @param[in] path - The BMC error log object path
+ * @param[in] dataIface - The DataInterface object
+ */
+void createServiceActions(const nlohmann::json& jsonCallouts,
+                          const std::string& path,
+                          const DataInterfaceBase& dataIface);
+} // namespace phal
+} // namespace pels
+} // namespace openpower