PEL: Support user supplied flag to indicate a fatal/terminating

User can supply SEVERITY_DETAIL=SYSTEM_TERM as part
of AdditionalData entry in the event log to set the
severity level in User Header of PEL

Tested: I ran unit test using docker. Also tested manually
by setting D-bus event log

Change-Id: I9205c084c32576734c2b5b4c79c273f8defde9d4
Signed-off-by: Vijay Lobo <vijaylobo@gmail.com>
diff --git a/extensions/openpower-pels/README.md b/extensions/openpower-pels/README.md
index 1aba263..c38d06d 100644
--- a/extensions/openpower-pels/README.md
+++ b/extensions/openpower-pels/README.md
@@ -45,6 +45,21 @@
 
 Note that TRUE is the only value supported.
 
+#### SEVERITY_DETAIL
+
+This is used when the passed in event log severity determines the PEL
+severity and a more granular PEL severity is needed beyond what the normal
+event log to PEL severity conversion could give.
+
+The syntax is:
+```
+SEVERITY_DETAIL=<SEVERITY_TYPE>
+e.g.
+SEVERITY_DETAIL=SYSTEM_TERM
+```
+Option Supported:
+- SYSTEM_TERM, changes the Severity value from 0x50 to 0x51
+
 #### ESEL
 
 This keyword's data contains a full PEL in string format.  This is how hostboot
diff --git a/extensions/openpower-pels/pel.cpp b/extensions/openpower-pels/pel.cpp
index f66d985..48dff51 100644
--- a/extensions/openpower-pels/pel.cpp
+++ b/extensions/openpower-pels/pel.cpp
@@ -55,7 +55,8 @@
 
     _ph = std::make_unique<PrivateHeader>(regEntry.componentID, obmcLogID,
                                           timestamp);
-    _uh = std::make_unique<UserHeader>(regEntry, severity, dataIface);
+    _uh = std::make_unique<UserHeader>(regEntry, severity, additionalData,
+                                       dataIface);
 
     // Extract any callouts embedded in an FFDC file.
     if (!ffdcFiles.empty())
diff --git a/extensions/openpower-pels/user_header.cpp b/extensions/openpower-pels/user_header.cpp
index 276c506..a7d8023 100644
--- a/extensions/openpower-pels/user_header.cpp
+++ b/extensions/openpower-pels/user_header.cpp
@@ -47,6 +47,7 @@
 
 UserHeader::UserHeader(const message::Entry& entry,
                        phosphor::logging::Entry::Level severity,
+                       const AdditionalData& additionalData,
                        const DataInterfaceBase& dataIface)
 {
     _header.id = static_cast<uint16_t>(SectionID::userHeader);
@@ -88,6 +89,18 @@
         }
     }
 
+    // Convert Critical error (0x50) to Critical Error-System Termination
+    // (0x51), if the AdditionalData is set to SYSTEM_TERM
+    auto sevLevel = additionalData.getValue("SEVERITY_DETAIL");
+    if ((_eventSeverity & 0xF0) == 0x50)
+    {
+        if (sevLevel.value_or("") == "SYSTEM_TERM")
+        {
+            // Change to Critical Error, System Termination
+            _eventSeverity = 0x51;
+        }
+    }
+
     // TODO: ibm-dev/dev/#1144 Handle manufacturing sev & action flags
 
     if (entry.eventType)
@@ -99,7 +112,6 @@
         // There are different default event types for info errors
         // vs non info ones.
         auto sevType = static_cast<SeverityType>(_eventSeverity & 0xF0);
-
         _eventType = (sevType == SeverityType::nonError)
                          ? static_cast<uint8_t>(EventType::miscInformational)
                          : static_cast<uint8_t>(EventType::notApplicable);
diff --git a/extensions/openpower-pels/user_header.hpp b/extensions/openpower-pels/user_header.hpp
index da9be6c..e17d0cf 100644
--- a/extensions/openpower-pels/user_header.hpp
+++ b/extensions/openpower-pels/user_header.hpp
@@ -44,10 +44,13 @@
      *
      * @param[in] entry - The message registry entry for this error
      * @param[in] severity - The OpenBMC event log severity for this error
+     * @param[in] additionalData - The AdditionalData properties in this
+     *                             error log
      * @param[in] dataIface - The DataInterface object
      */
     UserHeader(const message::Entry& entry,
                phosphor::logging::Entry::Level severity,
+               const AdditionalData& additionalData,
                const DataInterfaceBase& dataIface);
 
     /**
diff --git a/test/openpower-pels/user_header_test.cpp b/test/openpower-pels/user_header_test.cpp
index b7b6583..9c38ec1 100644
--- a/test/openpower-pels/user_header_test.cpp
+++ b/test/openpower-pels/user_header_test.cpp
@@ -112,8 +112,9 @@
         regEntry.eventScope = 2;
 
         MockDataInterface dataIface;
+        AdditionalData ad;
 
-        UserHeader uh(regEntry, phosphor::logging::Entry::Level::Error,
+        UserHeader uh(regEntry, phosphor::logging::Entry::Level::Error, ad,
                       dataIface);
 
         ASSERT_TRUE(uh.valid());
@@ -138,7 +139,7 @@
             // then set them to 0xFFFF.
             regEntry.actionFlags = std::nullopt;
 
-            UserHeader uh(regEntry, phosphor::logging::Entry::Level::Error,
+            UserHeader uh(regEntry, phosphor::logging::Entry::Level::Error, ad,
                           dataIface);
             EXPECT_EQ(uh.actionFlags(), 0xFFFF);
         }
@@ -152,6 +153,8 @@
         regEntry.subsystem = 5;
         regEntry.severity = {{"", 0x20}, {"systemB", 0x10}, {"systemA", 0x00}};
 
+        AdditionalData ad;
+
         MockDataInterface dataIface;
         std::vector<std::string> names1{"systemA"};
         std::vector<std::string> names2{"systemB"};
@@ -163,21 +166,21 @@
             .WillOnce(Return(names3));
 
         {
-            UserHeader uh(regEntry, phosphor::logging::Entry::Level::Error,
+            UserHeader uh(regEntry, phosphor::logging::Entry::Level::Error, ad,
                           dataIface);
 
             EXPECT_EQ(uh.severity(), 0x00);
         }
 
         {
-            UserHeader uh(regEntry, phosphor::logging::Entry::Level::Error,
+            UserHeader uh(regEntry, phosphor::logging::Entry::Level::Error, ad,
                           dataIface);
 
             EXPECT_EQ(uh.severity(), 0x10);
         }
 
         {
-            UserHeader uh(regEntry, phosphor::logging::Entry::Level::Error,
+            UserHeader uh(regEntry, phosphor::logging::Entry::Level::Error, ad,
                           dataIface);
 
             EXPECT_EQ(uh.severity(), 0x20);
@@ -200,11 +203,58 @@
     // Leave off severity
 
     MockDataInterface dataIface;
+    AdditionalData ad;
 
-    UserHeader uh(regEntry, phosphor::logging::Entry::Level::Error, dataIface);
+    UserHeader uh(regEntry, phosphor::logging::Entry::Level::Error, ad,
+                  dataIface);
     ASSERT_EQ(uh.severity(), 0x40);
 }
 
+// Test that the critical severity comes from the event log if not
+// in the message registry
+TEST(UserHeaderTest, UseEventLogSevCritTest)
+{
+    using namespace openpower::pels::message;
+    Entry regEntry;
+
+    regEntry.name = "test";
+    regEntry.subsystem = 5;
+    regEntry.actionFlags = 0xC000;
+    regEntry.eventType = 1;
+    regEntry.eventScope = 2;
+    // Leave off severity
+
+    MockDataInterface dataIface;
+    AdditionalData ad;
+
+    UserHeader uh(regEntry, phosphor::logging::Entry::Level::Critical, ad,
+                  dataIface);
+    ASSERT_EQ(uh.severity(), 0x50);
+}
+
+// Test that the critical severity comes from the event log if not
+// in the message registry and termination condition is set
+TEST(UserHeaderTest, UseEventLogSevCritTermTest)
+{
+    using namespace openpower::pels::message;
+    Entry regEntry;
+
+    regEntry.name = "test";
+    regEntry.subsystem = 5;
+    regEntry.actionFlags = 0xC000;
+    regEntry.eventType = 1;
+    regEntry.eventScope = 2;
+    // Leave off severity
+
+    MockDataInterface dataIface;
+    std::vector<std::string> adData{"SEVERITY_DETAIL=SYSTEM_TERM"};
+    AdditionalData ad{adData};
+
+    UserHeader uh(regEntry, phosphor::logging::Entry::Level::Critical, ad,
+                  dataIface);
+    ASSERT_EQ(uh.severity(), 0x51);
+}
+
 // Test that the optional event type & scope fields work
 TEST(UserHeaderTest, DefaultEventTypeScopeTest)
 {
@@ -217,8 +267,10 @@
     regEntry.actionFlags = 0xC000;
 
     MockDataInterface dataIface;
+    AdditionalData ad;
 
-    UserHeader uh(regEntry, phosphor::logging::Entry::Level::Error, dataIface);
+    UserHeader uh(regEntry, phosphor::logging::Entry::Level::Error, ad,
+                  dataIface);
 
     ASSERT_EQ(uh.eventType(), 0);
     ASSERT_EQ(uh.scope(), 0x03);