PEL: enable base infrastructure for SBE FFDC base PEL create

This commits provides the base infrastructure for SBE FFDC based
on createPELWithFFDCFiles`D-Bus method on the
org.open_power.Logging.PEL.

More details related to usage of this interface is documented
as part of extensions/openpower-pels/README.md.

In the PEL create interface if the type is custom and subtype
is 0xCB, PEL class function invokes SBE FFDC function to process
SBE FFDC to extract Hardware procedure added user data section and
callouts. SBE FFDC class appends the callout json and create
user data file based FFDC information and continue the normal
PEL create function.

SCOPE of this commit:
 - Add base infrastructure and control build only for "phal" supported
   systems. "phal" feature is mandatory requirement for processing
   SBE FFDC.
 - Add SBE FFDC raw information in PEL user data section

To enable this feature use the below meson build options
  meson build -Dopenpower-pel-extension=enabled -Dphal=enabled

Tested:

"Error Details": {
        "Message":"chipop timeout reported during SBE communication",
        "SRC6": [
           "0x2",
           "[0:15] chip position, [16:23] command class,
            [24:31] command type"
        ]
    },

"User Data 2": {
    "Section Version":          "1",
    "Sub-section type":         "203",
    "Created by":               "0x3500",
    "Data": [
        "FF DC 00 12 00 00 A1 01  00 8E CE 72 00 00 FF FE  |  ...........r....",
        "00 00 00 04 00 00 00 00  00 00 00 04 00 00 00 00  |  ................",
        "00 00 00 00 00 00 00 01  00 00 00 00 00 00 00 02  |  ................",
        "00 00 00 04 00 00 00 00  00 00 00 00 00 00 00 04  |  ................",
        "00 00 00 00 00 00 00 00                           |  ........"
    ]
}

Signed-off-by: Jayanth Othayoth <ojayanth@in.ibm.com>
Change-Id: I2200b3ba9c0977be13e71f25e87f0b16cb50ec5b
diff --git a/extensions/openpower-pels/README.md b/extensions/openpower-pels/README.md
index c38d06d..9c13374 100644
--- a/extensions/openpower-pels/README.md
+++ b/extensions/openpower-pels/README.md
@@ -642,4 +642,48 @@
 - not SeverityType::nonError
 - has a callout of any kind from the `FailingComponentType` structure
 
+## Self Boot Engine(SBE) First Failure Data Capture(FFDC) Support
+
+During SBE chip-op failure SBE creates FFDC with custom data format.
+SBE FFDC contains different packets, which include SBE internal failure related
+Trace and user data also Hardware procedure failure FFDC created by FAPI
+infrastructure. PEL infrastructure provides support to process SBE FFDC packets
+created by FAPI infrastructure during hardware procedure execution failures,
+also add callouts, user data section information based on FAPI processing
+in case non FAPI based failure, just keeps the raw FFDC data in the user section
+to support SBE parser plugins.
+
+
+CreatePELWithFFDCFiles D-Bus method on the `org.open_power.Logging.PEL`
+interface must be used when creating a new event log.
+
+To specify that an FFDC file contains SBE FFDC, the format value for that FFDC
+entry must be set to "custom", and the subtype field must be set to 0xCB:
+
+```
+using FFDC = std::tuple<CreateIface::FFDCFormat,
+                        uint8_t,
+                        uint8_t,
+                        sdbusplus::message::unix_fd>;
+
+FFDC ffdc{
+     CreateIface::FFDCFormat::custom,
+     0xCB, // SBE FFDC subtype
+     0x01, // SBE FFDC version, set to 0x01
+     fd};
+ ```
+
+"SRC6" Keyword in the additional data section should be populated with below.
+
+  - [0:15] chip position  (hex)
+  - [16:23] command class (hex)
+  - [24:31] command       (hex)
+
+e.g for GetSCOM
+
+   SRC6="0002A201"
+
+Note: "phal" build-time configure option should be "enabled" to enable this
+       feature.
+
 [1]: https://github.com/openbmc/docs/blob/master/designs/fail-boot-on-hw-error.md
diff --git a/extensions/openpower-pels/meson.build b/extensions/openpower-pels/meson.build
index b00d0ad..068f870 100644
--- a/extensions/openpower-pels/meson.build
+++ b/extensions/openpower-pels/meson.build
@@ -29,6 +29,16 @@
     )
 endif
 
+extra_sources = []
+build_phal = get_option('phal').enabled()
+
+if build_phal
+    extra_sources += [
+        'sbe_ffdc_handler.cpp',
+    ]
+    add_project_arguments('-DSBE_FFDC_SUPPORTED', language : ['c','cpp'])
+endif
+
 libpel_sources = files(
     'ascii_string.cpp',
     'bcd_time.cpp',
@@ -54,6 +64,7 @@
     'service_indicators.cpp',
     'severity.cpp',
     'user_header.cpp',
+    extra_sources,
 )
 
 libpel_deps = [
diff --git a/extensions/openpower-pels/pel.cpp b/extensions/openpower-pels/pel.cpp
index 1add587..f1a73c4 100644
--- a/extensions/openpower-pels/pel.cpp
+++ b/extensions/openpower-pels/pel.cpp
@@ -28,6 +28,10 @@
 #include "stream.hpp"
 #include "user_data_formats.hpp"
 
+#ifdef SBE_FFDC_SUPPORTED
+#include "sbe_ffdc_handler.hpp"
+#endif
+
 #include <fmt/format.h>
 #include <sys/stat.h>
 #include <unistd.h>
@@ -48,9 +52,33 @@
 
 PEL::PEL(const message::Entry& regEntry, uint32_t obmcLogID, uint64_t timestamp,
          phosphor::logging::Entry::Level severity,
-         const AdditionalData& additionalData, const PelFFDC& ffdcFiles,
+         const AdditionalData& additionalData, const PelFFDC& ffdcFilesIn,
          const DataInterfaceBase& dataIface)
 {
+    // No changes in input, for non SBE error related requests
+    PelFFDC ffdcFiles = ffdcFilesIn;
+
+#ifdef SBE_FFDC_SUPPORTED
+    // Add sbe ffdc processed data into ffdcfiles.
+    namespace sbe = openpower::pels::sbe;
+    auto processReq =
+        std::any_of(ffdcFiles.begin(), ffdcFiles.end(), [](const auto& file) {
+            return file.format == UserDataFormat::custom &&
+                   file.subType == sbe::sbeFFDCSubType;
+        });
+    // sbeFFDC can't be destroyed until the end of the PEL constructor
+    // because it needs to keep around the FFDC Files to be used below.
+    std::unique_ptr<sbe::SbeFFDC> sbeFFDCPtr;
+    if (processReq)
+    {
+        sbeFFDCPtr =
+            std::make_unique<sbe::SbeFFDC>(additionalData, ffdcFilesIn);
+        const auto& sbeFFDCFiles = sbeFFDCPtr->getSbeFFDC();
+        ffdcFiles.insert(ffdcFiles.end(), sbeFFDCFiles.begin(),
+                         sbeFFDCFiles.end());
+    }
+#endif
+
     std::map<std::string, std::vector<std::string>> debugData;
     nlohmann::json callouts;
 
diff --git a/extensions/openpower-pels/sbe_ffdc_handler.cpp b/extensions/openpower-pels/sbe_ffdc_handler.cpp
new file mode 100644
index 0000000..55e3cbe
--- /dev/null
+++ b/extensions/openpower-pels/sbe_ffdc_handler.cpp
@@ -0,0 +1,74 @@
+/**
+ * Copyright © 2021 IBM Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "sbe_ffdc_handler.hpp"
+
+#include <fmt/format.h>
+
+#include <phosphor-logging/log.hpp>
+
+namespace openpower
+{
+namespace pels
+{
+namespace sbe
+{
+
+using namespace phosphor::logging;
+
+SbeFFDC::SbeFFDC(const AdditionalData& aData, const PelFFDC& files)
+{
+    log<level::INFO>("SBE FFDC processing requested");
+
+    // SRC6 field in the additional data contains Processor position
+    // associated to the SBE FFDC
+    //"[0:15] chip position"
+    auto src6 = aData.getValue("SRC6");
+    if (src6 == std::nullopt)
+    {
+        log<level::ERR>("Fail to extract SRC6 data: failing to get proc index");
+        return;
+    }
+    try
+    {
+        procPos = std::stoi((src6.value()).substr(0, 4));
+    }
+    catch (std::exception& err)
+    {
+        log<level::ERR>(
+            fmt::format("Conversion failure errormsg({})", err.what()).c_str());
+        return;
+    }
+
+    if (files.empty())
+    {
+        log<level::INFO>("SbeFFDC : No files found, skipping ffdc processing");
+        return;
+    }
+
+    for (const auto& file : files)
+    {
+        if ((file.format == UserDataFormat::custom) &&
+            (file.subType == sbeFFDCSubType))
+        {
+            // TODO Process SBE file.
+        }
+    }
+}
+
+} // namespace sbe
+} // namespace pels
+} // namespace openpower
diff --git a/extensions/openpower-pels/sbe_ffdc_handler.hpp b/extensions/openpower-pels/sbe_ffdc_handler.hpp
new file mode 100644
index 0000000..efdaa03
--- /dev/null
+++ b/extensions/openpower-pels/sbe_ffdc_handler.hpp
@@ -0,0 +1,109 @@
+#pragma once
+
+#include "additional_data.hpp"
+#include "pel.hpp"
+
+namespace openpower
+{
+namespace pels
+{
+namespace sbe
+{
+
+// SBE FFDC sub type.
+constexpr uint8_t sbeFFDCSubType = 0xCB;
+
+/** @class SbeFFDC
+ *
+ * @brief This class provides higher level interface to process SBE ffdc
+ * for PEL based error logging infrastructure.
+ * Key Functionalities included here
+ *    - Process the SBE FFDC data with the help of FAPI infrastructure and
+ *      and create PEL required format Callout and user data for hardware
+ *      procedure failures specific reason code
+ *    - Add the user data section with SBE FFDC data to support SBE provided
+ *      parser tool usage.
+ *    - Any SBE FFDC processing will result additional log message in journal
+ *      and will continue to create Error log with available data. This is to
+ *      help user to analyse the failure.
+ */
+class SbeFFDC
+{
+  public:
+    SbeFFDC() = delete;
+    SbeFFDC(const SbeFFDC&) = delete;
+    SbeFFDC& operator=(const SbeFFDC&) = delete;
+    SbeFFDC(SbeFFDC&&) = delete;
+    SbeFFDC& operator=(SbeFFDC&&) = delete;
+
+    /**
+     * @brief Constructor
+     *
+     * Create PEL required format data from SBE provided FFDC data.
+     *
+     * @param[in] data - The AdditionalData properties in this PEL event
+     * @param[in] files - FFDC files that go into UserData sections
+     */
+    SbeFFDC(const AdditionalData& data, const PelFFDC& files);
+
+    /**
+     * @brief Destructor
+     *
+     * Deletes the temporary files
+     */
+    ~SbeFFDC()
+    {
+
+        try
+        {
+            for (auto path : paths)
+            {
+                if (!path.empty())
+                {
+                    // Delete temporary file from file system
+                    std::error_code ec;
+                    std::filesystem::remove(path, ec);
+                    // Clear path to indicate file has been deleted
+                    path.clear();
+                }
+            }
+        }
+        catch (...)
+        {
+            // Destructors should not throw exceptions
+        }
+    }
+
+    /**
+     * @brief Helper function to return FFDC files information, which
+     *        includes SBE FFDC specific callout information.
+     *
+     * return PelFFDC - pel formated FFDC files.
+     */
+    const PelFFDC& getSbeFFDC()
+    {
+        return ffdcFiles;
+    }
+
+  private:
+    /**
+     * @brief  Temporary files path information created as part of FFDC
+     *         processing.
+     */
+    std::vector<std::filesystem::path> paths;
+
+    /**
+     * @brief PEL FFDC files, which includes the user data sections and the
+     *        added callout details if any, found during SBE FFDC processing.
+     */
+    PelFFDC ffdcFiles;
+
+    /**
+     * @brief Processor position associated to SBE FFDC
+     */
+    uint32_t procPos;
+};
+
+} // namespace sbe
+} // namespace pels
+} // namespace openpower
diff --git a/meson.build b/meson.build
index 81d5f07..0bbf14b 100644
--- a/meson.build
+++ b/meson.build
@@ -71,6 +71,7 @@
 conf_data = configuration_data()
 conf_data.set('error_cap', get_option('error_cap'))
 conf_data.set('error_info_cap', get_option('error_info_cap'))
+
 configure_file(
     input: 'config.h.meson',
     output: 'config.h',
diff --git a/meson_options.txt b/meson_options.txt
index d27f124..44869ea 100644
--- a/meson_options.txt
+++ b/meson_options.txt
@@ -26,3 +26,10 @@
     value: 10,
     description: 'Cap on informational (and below) severity errors',
 )
+
+option(
+    'phal',
+    type: 'feature',
+    value: 'disabled',
+    description: 'Enable support for PHAL',
+)