PHAL: Set HardwareIsolation policy before start the host

- The HardwareIsolation (aka guard) policy is used to prevent
  the HardwareIsolation functionality during the boot of the host
  by the user.

- In this patch, using that policy flag to ignore the isolated hardware
  records to apply during the start of the host from the BMC context.

- By default, it will be set as "true" before starting the host to boot
  if the HardwareIsolation policy is not present or failed to read that
  policy.

  - Created the error log with procedure callout if failed to read
    the HardwareIsolation policy.

Tested:
- Verified the HWAS_STATE of the isolated hardware, is not applied when
  the HardwareIsolation policy is enabled.

- Verified the HWAS_STATE of the isolated hardware, is applied when
  the HardwareIsolation policy is disabled.

- Verified the HWAS_STATE of the isolated hardware, is applied when
  the HardwareIsolation policy is not present.

- PEL for the third test case.

```
{
"Private Header": {
    "Section Version":          "1",
    "Sub-section type":         "0",
    "Created by":               "0x3000",
...
"User Header": {
    "Section Version":          "1",
    "Sub-section type":         "0",
    "Log Committed by":         "0x2000",
    "Subsystem":                "CEC Hardware",
    "Event Scope":              "Entire Platform",
    "Event Severity":           "Unrecoverable Error",
    "Event Type":               "Not Applicable",
    "Action Flags": [
                                "Service Action Required",
                                "Report Externally",
                                "HMC Call Home"
    ],
    "Host Transmission":        "Not Sent",
    "HMC Transmission":         "Not Sent"
},
...
"Primary SRC": {
    "Section Version":          "1",
    "Sub-section type":         "1",
    "Created by":               "0x3000",
...
    "Error Details": {
        "Message":              "Failure occured during boot process"
    },
    "Valid Word Count":         "0x09",
    "Reference Code":           "BD503001",
...
    "Callout Section": {
        "Callout Count":        "1",
        "Callouts": [{
            "FRU Type":         "Maintenance Procedure Required",
            "Priority":         "Medium Priority",
            "Procedure":        "BMC0001"
        }]
    }
...
"User Data 1": {
    "Section Version": "1",
    "Sub-section type": "1",
    "Created by": "0x2000",
    "REASON_FOR_PEL": "Failed to read the HardwareIsolation policy from the path [/xyz/openbmc_project/hardware_isolation/allow_hw_isolation] interface [xyz.openbmc_project.Object.Enable]. Continuing with default mode(allow_hw_isolation)",
    "_PID": "681"
},
"User Data 2": {
    "Section Version": "1",
    "Sub-section type": "1",
    "Created by": "0x2000",
    "Data": [
        {
            "Priority": "M",
            "Procedure": "BMC0001"
        }
    ]
}
}
```

Signed-off-by: Ramesh Iyyar <rameshi1@in.ibm.com>
Change-Id: I2d7e33ad1e6af69b150d6637619c17db5b9a7151
diff --git a/procedures/phal/start_host.cpp b/procedures/phal/start_host.cpp
index db323ca..01cada9 100644
--- a/procedures/phal/start_host.cpp
+++ b/procedures/phal/start_host.cpp
@@ -14,6 +14,7 @@
 #include <libekb.H>
 
 #include <ext_interface.hpp>
+#include <nlohmann/json.hpp>
 #include <phosphor-logging/log.hpp>
 #include <registration.hpp>
 
@@ -169,6 +170,114 @@
 }
 
 /**
+ * @brief Helper function to create error log (aka PEL) with
+ *        procedure callout for the hardware isolation policy
+ *        settings failures.
+ *
+ * @param[in] procedureCode - The procedure code to include in the callout
+ * @param[in] priority - The priority for the procedure callout
+ * @param[in] additionalData - The additional data to include in the error log
+ *
+ * @return void
+ */
+static void
+    createPELForHwIsolationSettingsErr(const std::string& procedureCode,
+                                       const std::string& priority,
+                                       const pel::FFDCData& additionalData)
+{
+    try
+    {
+        using json = nlohmann::json;
+
+        json jsonCalloutDataList;
+        jsonCalloutDataList = json::array();
+        json jsonCalloutData;
+        jsonCalloutData["Procedure"] = procedureCode;
+        jsonCalloutData["Priority"] = priority;
+        jsonCalloutDataList.emplace_back(jsonCalloutData);
+
+        openpower::pel::createErrorPEL("org.open_power.PHAL.Error.Boot",
+                                       jsonCalloutDataList, additionalData);
+    }
+    catch (const std::exception& e)
+    {
+        // Don't throw exception since the caller might call in the error path
+        // and even we should allow the hardware isolation by default.
+        log<level::ERR>(
+            fmt::format("Exception [{}], failed to create the error log "
+                        "for the hardware isolation policy settings failures.",
+                        e.what())
+                .c_str());
+    }
+}
+
+/**
+ * @brief Helper function to decide the hardware isolation (aka guard)
+ *
+ * @return xyz.openbmc_project.Object.Enable::Enabled value on success
+ *         true on failure since hardware isolation feature should be
+ *         enabled by default.
+ */
+static bool allowHwIsolation()
+{
+    bool allowHwIsolation{true};
+
+    constexpr auto hwIsolationPolicyObjPath =
+        "/xyz/openbmc_project/hardware_isolation/allow_hw_isolation";
+    constexpr auto hwIsolationPolicyIface = "xyz.openbmc_project.Object.Enable";
+
+    try
+    {
+        auto bus = sdbusplus::bus::new_default();
+
+        std::string service = util::getService(bus, hwIsolationPolicyObjPath,
+                                               hwIsolationPolicyIface);
+
+        auto method =
+            bus.new_method_call(service.c_str(), hwIsolationPolicyObjPath,
+                                "org.freedesktop.DBus.Properties", "Get");
+        method.append(hwIsolationPolicyIface, "Enabled");
+
+        auto reply = bus.call(method);
+
+        std::variant<bool> resp;
+
+        reply.read(resp);
+
+        if (const bool* enabledPropVal = std::get_if<bool>(&resp))
+        {
+            allowHwIsolation = *enabledPropVal;
+        }
+        else
+        {
+            const auto trace{fmt::format(
+                "Failed to read the HardwareIsolation policy "
+                "from the path [{}] interface [{}]. Continuing with "
+                "default mode(allow_hw_isolation)",
+                hwIsolationPolicyObjPath, hwIsolationPolicyIface)};
+
+            log<level::ERR>(trace.c_str());
+            createPELForHwIsolationSettingsErr("BMC0001", "M",
+                                               {{"REASON_FOR_PEL", trace}});
+        }
+    }
+    catch (const sdbusplus::exception::exception& e)
+    {
+        const auto trace{fmt::format(
+            "Exception [{}] to get the HardwareIsolation policy "
+            "from the path [{}] interface [{}]. Continuing with "
+            "default mode (allow_hw_isolation)",
+            e.what(), hwIsolationPolicyObjPath, hwIsolationPolicyIface)};
+
+        log<level::ERR>(trace.c_str());
+        createPELForHwIsolationSettingsErr("BMC0001", "M",
+                                           {{"REASON_FOR_PEL", trace}});
+    }
+
+    return allowHwIsolation;
+}
+
+/**
  * @brief Starts the self boot engine on POWER processor position 0
  *        to kick off a boot.
  * @return void
@@ -179,6 +288,17 @@
     {
         phal_init();
         ipl_set_type(iplType);
+
+        /**
+         * Don't apply guard records if the HardwareIsolation (aka guard)
+         * the policy is disabled (false). By default, libipl will apply
+         * guard records.
+         */
+        if (!allowHwIsolation())
+        {
+            ipl_disable_guard();
+        }
+
         if (iplType == IPL_TYPE_NORMAL)
         {
             // Update SEEPROM side only for NORMAL boot