ATTN:ti_handler Add TI data to PEL

Parse TI data buffer and store in PEL.

Signed-off-by: Ben Tyner <ben.tyner@ibm.com>
Change-Id: I5baf4c14719f510281c2943ea681c6db53c9c87e
diff --git a/attn/attn_handler.cpp b/attn/attn_handler.cpp
index ab72ab7..f34dd2e 100644
--- a/attn/attn_handler.cpp
+++ b/attn/attn_handler.cpp
@@ -268,10 +268,6 @@
         }
     }
 
-    // Note: If we want to support running this application on architectures
-    // of different endian-ness we need to handler that here. The TI data
-    // will always be written in big-endian order.
-
     // If TI area exists and is marked valid we can assume TI occurred
     if ((nullptr != tiInfo) && (0 != tiInfo[0]))
     {
@@ -281,12 +277,19 @@
 
         // trace a few known TI data area values
         std::stringstream ss; // log message stream
-        ss << "TI data command = " << tiDataArea->command;
+
+        ss << "TI data command = " << (int)tiDataArea->command;
         trace<level::INFO>(ss.str().c_str());
-        ss << "TI data SRC format = " << tiDataArea->srcFormat;
+        ss.str(std::string());
+
+        ss << "TI data SRC format = " << (int)tiDataArea->srcFormat;
         trace<level::INFO>(ss.str().c_str());
-        ss << "TI data hb_terminate_type = " << tiDataArea->hbTerminateType;
+        ss.str(std::string());
+
+        ss << "TI data hb_terminate_type = "
+           << (int)tiDataArea->hbTerminateType;
         trace<level::INFO>(ss.str().c_str());
+        ss.str(std::string());
 
         if (true == (i_attention->getConfig()->getFlag(enTerminate)))
         {
diff --git a/attn/attn_logging.cpp b/attn/attn_logging.cpp
index 2d4d4db..cbe3afd 100644
--- a/attn/attn_logging.cpp
+++ b/attn/attn_logging.cpp
@@ -93,13 +93,9 @@
 }
 
 /** @brief commit special attention TI event to log */
-void eventTerminate()
+void eventTerminate(std::map<std::string, std::string> i_additionalData)
 {
-    std::map<std::string, std::string> additionalData;
-
-    additionalData["_PID"] = std::to_string(getpid());
-
-    event(EventType::Terminate, additionalData);
+    event(EventType::Terminate, i_additionalData);
 }
 
 /** @brief commit SBE vital event to log */
diff --git a/attn/attn_logging.hpp b/attn/attn_logging.hpp
index 2446ba6..e21418a 100644
--- a/attn/attn_logging.hpp
+++ b/attn/attn_logging.hpp
@@ -34,7 +34,7 @@
 void eventCheckstop(std::map<std::string, std::string>& i_errors);
 
 /** @brief commit special attention TI event to log */
-void eventTerminate();
+void eventTerminate(std::map<std::string, std::string> i_additionalData);
 
 /** @brief commit SBE vital event to log */
 void eventVital();
diff --git a/attn/ti_handler.cpp b/attn/ti_handler.cpp
index 403cd8c..a318e56 100644
--- a/attn/ti_handler.cpp
+++ b/attn/ti_handler.cpp
@@ -4,6 +4,9 @@
 #include <sdbusplus/bus.hpp>
 #include <sdbusplus/exception.hpp>
 
+#include <iomanip>
+#include <iostream>
+
 namespace attn
 {
 
@@ -12,10 +15,15 @@
 {
     int rc = RC_NOT_HANDLED; // assume TI not handled
 
+    // PHYP TI
     if (0xa1 == i_tiDataArea->command)
     {
-        // Use the systemd service manager object interface to call the
-        // start unit method with the obmc-host-diagnostic-mode target.
+        // Generate PEL with TI info
+        std::map<std::string, std::string> i_tiDataAreaMap;
+        parsePhypOpalTiInfo(i_tiDataAreaMap, i_tiDataArea); // human readable
+        parseRawTiInfo(i_tiDataAreaMap, i_tiDataArea);      // hex dump
+        eventTerminate(i_tiDataAreaMap);                    // generate PEL
+
         auto bus    = sdbusplus::bus::new_system();
         auto method = bus.new_method_call(
             "org.freedesktop.systemd1", "/org/freedesktop/systemd1",
@@ -34,16 +42,133 @@
             trace<level::INFO>("start obmc-host-quiesce target");
             method.append("obmc-host-quiesce@0.target");
         }
+
         method.append("replace"); // mode = replace conflicting queued jobs
         bus.call_noreply(method); // start the service
 
         rc = RC_SUCCESS;
     }
+    // HB TI
+    else
+    {
+        // Generate PEL with TI info
+        std::map<std::string, std::string> i_tiDataAreaMap;
+        parseHbTiInfo(i_tiDataAreaMap, i_tiDataArea);  // human readable
+        parseRawTiInfo(i_tiDataAreaMap, i_tiDataArea); // hex dump
+        eventTerminate(i_tiDataAreaMap);               // generate PEL
+    }
 
     return rc;
 }
 
-/** @brief Read autoreboot property **/
+/** @brief Parse the TI info data area into map as raw 32-bit fields */
+void parseRawTiInfo(std::map<std::string, std::string>& i_map,
+                    TiDataArea* i_buffer)
+{
+
+    uint32_t* tiDataArea = (uint32_t*)i_buffer;
+    std::stringstream ss;
+
+    ss << std::hex << std::setfill('0');
+    ss << "raw:";
+    while (tiDataArea <= (uint32_t*)((char*)i_buffer + sizeof(TiDataArea)))
+    {
+        ss << std::setw(8) << std::endl << be32toh(*tiDataArea);
+        tiDataArea++;
+    }
+
+    std::string key, value;
+    char delim = ':';
+
+    while (std::getline(ss, key, delim))
+    {
+        std::getline(ss, value, delim);
+        i_map[key] = value;
+    }
+}
+
+/** @brief Parse the TI info data area into map as PHYP/OPAL data */
+void parsePhypOpalTiInfo(std::map<std::string, std::string>& i_map,
+                         TiDataArea* i_tiDataArea)
+{
+    std::stringstream ss;
+
+    ss << std::hex << std::showbase;
+    ss << "0x00 TI Area Valid:" << (int)i_tiDataArea->tiAreaValid << ":";
+    ss << "0x01 Command:" << (int)i_tiDataArea->command << ":";
+    ss << "0x02 Num. Data Bytes:" << be16toh(i_tiDataArea->numDataBytes) << ":";
+    ss << "0x04 Reserved:" << (int)i_tiDataArea->reserved1 << ":";
+    ss << "0x06 HWDump Type:" << be16toh(i_tiDataArea->hardwareDumpType) << ":";
+    ss << "0x08 SRC Format:" << (int)i_tiDataArea->srcFormat << ":";
+    ss << "0x09 SRC Flags:" << (int)i_tiDataArea->srcFlags << ":";
+    ss << "0x0a Num. ASCII Words:" << (int)i_tiDataArea->numAsciiWords << ":";
+    ss << "0x0b Num. Hex Words:" << (int)i_tiDataArea->numHexWords << ":";
+    ss << "0x0e Length of SRC:" << be16toh(i_tiDataArea->lenSrc) << ":";
+    ss << "0x10 SRC Word 12:" << be32toh(i_tiDataArea->srcWord12HbWord0) << ":";
+    ss << "0x14 SRC Word 13:" << be32toh(i_tiDataArea->srcWord13HbWord2) << ":";
+    ss << "0x18 SRC Word 14:" << be32toh(i_tiDataArea->srcWord14HbWord3) << ":";
+    ss << "0x1c SRC Word 15:" << be32toh(i_tiDataArea->srcWord15HbWord4) << ":";
+    ss << "0x20 SRC Word 16:" << be32toh(i_tiDataArea->srcWord16HbWord5) << ":";
+    ss << "0x24 SRC Word 17:" << be32toh(i_tiDataArea->srcWord17HbWord6) << ":";
+    ss << "0x28 SRC Word 18:" << be32toh(i_tiDataArea->srcWord18HbWord7) << ":";
+    ss << "0x2c SRC Word 19:" << be32toh(i_tiDataArea->srcWord19HbWord8) << ":";
+    ss << "0x30 ASCII Data:" << be32toh(i_tiDataArea->asciiData0) << ":";
+    ss << "0x34 ASCII Data:" << be32toh(i_tiDataArea->asciiData1) << ":";
+    ss << "0x38 ASCII Data:" << be32toh(i_tiDataArea->asciiData2) << ":";
+    ss << "0x3c ASCII Data:" << be32toh(i_tiDataArea->asciiData3) << ":";
+    ss << "0x40 ASCII Data:" << be32toh(i_tiDataArea->asciiData4) << ":";
+    ss << "0x44 ASCII Data:" << be32toh(i_tiDataArea->asciiData5) << ":";
+    ss << "0x48 ASCII Data:" << be32toh(i_tiDataArea->asciiData6) << ":";
+    ss << "0x4c ASCII Data:" << be32toh(i_tiDataArea->asciiData7) << ":";
+    ss << "0x50 Location:" << (int)i_tiDataArea->location << ":";
+    ss << "0x51 Code Sections:" << (int)i_tiDataArea->codeSection << ":";
+    ss << "0x52 Additional Size:" << (int)i_tiDataArea->additionalSize << ":";
+    ss << "0x53 Additional Data:" << (int)i_tiDataArea->andData;
+
+    std::string key, value;
+    char delim = ':';
+
+    while (std::getline(ss, key, delim))
+    {
+        std::getline(ss, value, delim);
+        i_map[key] = value;
+    }
+}
+
+/** @brief Parse the TI info data area into map as hostboot data */
+void parseHbTiInfo(std::map<std::string, std::string>& i_map,
+                   TiDataArea* i_tiDataArea)
+{
+    std::stringstream ss;
+
+    ss << std::hex << std::showbase;
+    ss << "0x00 TI Area Valid:" << (int)i_tiDataArea->tiAreaValid << ":";
+    ss << "0x04 Reserved:" << (int)i_tiDataArea->reserved1 << ":";
+    ss << "0x05 HB_Term. Type:" << (int)i_tiDataArea->hbTerminateType << ":";
+    ss << "0x0c HB Dump Flag:" << (int)i_tiDataArea->hbDumpFlag << ":";
+    ss << "0x0d Source:" << (int)i_tiDataArea->source << ":";
+    ss << "0x10 HB Word 0:" << be32toh(i_tiDataArea->srcWord12HbWord0) << ":";
+    ss << "0x14 HB Word 2:" << be32toh(i_tiDataArea->srcWord13HbWord2) << ":";
+    ss << "0x18 HB Word 3:" << be32toh(i_tiDataArea->srcWord14HbWord3) << ":";
+    ss << "0x1c HB Word 4:" << be32toh(i_tiDataArea->srcWord15HbWord4) << ":";
+    ss << "0x20 HB Word 5:" << be32toh(i_tiDataArea->srcWord16HbWord5) << ":";
+    ss << "0x24 HB Word 6:" << be32toh(i_tiDataArea->srcWord17HbWord6) << ":";
+    ss << "0x28 HB Word 7:" << be32toh(i_tiDataArea->srcWord18HbWord7) << ":";
+    ss << "0x2c HB Word 8:" << be32toh(i_tiDataArea->srcWord19HbWord8) << ":";
+    ss << "0x30 error_data:" << be32toh(i_tiDataArea->asciiData0) << ":";
+    ss << "0x34 EID:" << be32toh(i_tiDataArea->asciiData1);
+
+    std::string key, value;
+    char delim = ':';
+
+    while (std::getline(ss, key, delim))
+    {
+        std::getline(ss, value, delim);
+        i_map[key] = value;
+    }
+}
+
+/** @brief Read state of autoreboot propertyi via dbus */
 bool autoRebootEnabled()
 {
     // Use dbus get-property interface to read the autoreboot property
@@ -52,14 +177,18 @@
         bus.new_method_call("xyz.openbmc_project.Settings",
                             "/xyz/openbmc_project/control/host0/auto_reboot",
                             "org.freedesktop.DBus.Properties", "Get");
+
     method.append("xyz.openbmc_project.Control.Boot.RebootPolicy",
                   "AutoReboot");
+
     try
     {
         auto reply = bus.call(method);
+
         std::variant<bool> result;
         reply.read(result);
         auto autoReboot = std::get<bool>(result);
+
         if (autoReboot)
         {
             trace<level::INFO>("Auto reboot enabled");
@@ -73,11 +202,11 @@
     }
     catch (const sdbusplus::exception::SdBusError& ec)
     {
-        // Error reading autoreboot
         std::string traceMessage =
             "Error in AutoReboot Get: " + std::string(ec.what());
         trace<level::INFO>(traceMessage.c_str());
         return false; // assume autoreboot disabled
     }
 }
+
 } // namespace attn
diff --git a/attn/ti_handler.hpp b/attn/ti_handler.hpp
index 6cf2a5b..99af51e 100644
--- a/attn/ti_handler.hpp
+++ b/attn/ti_handler.hpp
@@ -54,10 +54,35 @@
 int tiHandler(TiDataArea* i_tiDataArea);
 
 /**
+ * @brief Parse TI info data as raw 32-bit fields
+ *
+ * Read the TI data in as 32-bit fields and place into map.
+ */
+void parseRawTiInfo(std::map<std::string, std::string>& i_map,
+                    TiDataArea* i_buffer);
+
+/**
+ * @brief Parse TI info data as PHYP/OPAL data
+ *
+ * Read the TI data, parse as PHYP/OPAL data and place into map.
+ */
+void parsePhypOpalTiInfo(std::map<std::string, std::string>& i_map,
+                         TiDataArea* i_tiDataArea);
+
+/**
+ * @brief Parse TI info data as hostboot data
+ *
+ * Read the TI data, parse as hostboot data and place into map.
+ */
+void parseHbTiInfo(std::map<std::string, std::string>& i_map,
+                   TiDataArea* i_tiDataArea);
+
+/**
  * @brief Read autoreboot property
  *
  * Read the autoreboot property via dbus. This status will be used to
  * determine whether to either mpipl or quiesce the host on TI condition.
  */
 bool autoRebootEnabled();
+
 } // namespace attn
diff --git a/test/end2end/logging.cpp b/test/end2end/logging.cpp
index f645947..5163c4e 100644
--- a/test/end2end/logging.cpp
+++ b/test/end2end/logging.cpp
@@ -31,10 +31,18 @@
     std::cout << "event: attention fail" << i_error << std::endl;
 }
 
-void eventTerminate()
+void eventTerminate(std::map<std::string, std::string> i_additionalData)
 {
     std::cout << "event: terminate" << std::endl;
+
+    std::map<std::string, std::string>::iterator itr;
+    for (itr = i_additionalData.begin(); itr != i_additionalData.end(); ++itr)
+    {
+        std::cout << '\t' << itr->first << '\t' << itr->second << '\n';
+    }
+    std::cout << std::endl;
 }
+
 void eventVital()
 {
     std::cout << "event: vital" << std::endl;