From 600d15afba0c72ab4e7bf6769dccffffe08ca5aa Mon Sep 17 00:00:00 2001 From: Harisuddin Mohamed Isa Date: Fri, 20 Dec 2019 12:42:26 +0800 Subject: PEL: Print action flags into JSON aligned "User Header": { "Section Version": "1", "Sub-section type": "0", "Log Committed by": "0x4552", "Subsystem": "System Hypervisor Firmware", "Event Scope": "Entire Platform", "Event Severity": "Informational Event", "Event Type": "Miscellaneous, Informational Only", "Action Flags": [ "Report Externally" ] } Testing: Manually run peltool and verified output Signed-off-by: Harisuddin Mohamed Isa Change-Id: Ie8376953b5f1baa093fc0aa9564d50cd4208564e --- extensions/openpower-pels/hexdump.cpp | 139 -------------------- extensions/openpower-pels/hexdump.hpp | 33 ----- extensions/openpower-pels/json_utils.cpp | 197 ++++++++++++++++++++++++++++ extensions/openpower-pels/json_utils.hpp | 55 ++++++++ extensions/openpower-pels/openpower-pels.mk | 2 +- extensions/openpower-pels/pel.cpp | 11 +- extensions/openpower-pels/pel_values.cpp | 18 ++- extensions/openpower-pels/pel_values.hpp | 10 ++ extensions/openpower-pels/user_header.cpp | 23 ++-- test/openpower-pels/Makefile.include | 2 +- 10 files changed, 301 insertions(+), 189 deletions(-) delete mode 100644 extensions/openpower-pels/hexdump.cpp delete mode 100644 extensions/openpower-pels/hexdump.hpp create mode 100644 extensions/openpower-pels/json_utils.cpp create mode 100644 extensions/openpower-pels/json_utils.hpp diff --git a/extensions/openpower-pels/hexdump.cpp b/extensions/openpower-pels/hexdump.cpp deleted file mode 100644 index ee4aef8..0000000 --- a/extensions/openpower-pels/hexdump.cpp +++ /dev/null @@ -1,139 +0,0 @@ -/** - * Copyright © 2019 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 "hexdump.hpp" - -#include - -#include -#include -#include - -namespace openpower -{ -namespace pels -{ - -std::string escapeJSON(const std::string& input) -{ - std::string output; - output.reserve(input.length()); - - for (const auto c : input) - { - switch (c) - { - case '"': - output += "\\\""; - break; - case '/': - output += "\\/"; - break; - case '\b': - output += "\\b"; - break; - case '\f': - output += "\\f"; - break; - case '\n': - output += "\\n"; - break; - case '\r': - output += "\\r"; - break; - case '\t': - output += "\\t"; - break; - case '\\': - output += "\\\\"; - break; - default: - output += c; - break; - } - } - - return output; -} -char* dumpHex(const void* data, size_t size) -{ - const int symbolSize = 100; - char* buffer = (char*)calloc(10 * size, sizeof(char)); - char* symbol = (char*)calloc(symbolSize, sizeof(char)); - char ascii[17]; - size_t i, j; - ascii[16] = '\0'; - for (i = 0; i < size; ++i) - { - if (i % 16 == 0) - { - strcat(buffer, "\""); - } - snprintf(symbol, symbolSize, "%02X ", ((unsigned char*)data)[i]); - strcat(buffer, symbol); - memset(symbol, 0, strlen(symbol)); - if (((unsigned char*)data)[i] >= ' ' && - ((unsigned char*)data)[i] <= '~') - { - ascii[i % 16] = ((unsigned char*)data)[i]; - } - else - { - ascii[i % 16] = '.'; - } - if ((i + 1) % 8 == 0 || i + 1 == size) - { - std::string asciiString(ascii); - asciiString = escapeJSON(asciiString); - const char* asciiToPrint = asciiString.c_str(); - strcat(buffer, " "); - if ((i + 1) % 16 == 0) - { - if (i + 1 != size) - { - snprintf(symbol, symbolSize, "| %s\", \n ", asciiToPrint); - } - else - { - snprintf(symbol, symbolSize, "| %s\" \n ", asciiToPrint); - } - strcat(buffer, symbol); - memset(symbol, 0, strlen(symbol)); - } - else if (i + 1 == size) - { - ascii[(i + 1) % 16] = '\0'; - if ((i + 1) % 16 <= 8) - { - strcat(buffer, " "); - } - for (j = (i + 1) % 16; j < 16; ++j) - { - strcat(buffer, " "); - } - std::string asciiString2(ascii); - asciiString2 = escapeJSON(asciiString2); - asciiToPrint = asciiString2.c_str(); - snprintf(symbol, symbolSize, "| %s\" \n ", asciiToPrint); - strcat(buffer, symbol); - memset(symbol, 0, strlen(symbol)); - } - } - } - free(symbol); - return buffer; -} -} // namespace pels -} // namespace openpower diff --git a/extensions/openpower-pels/hexdump.hpp b/extensions/openpower-pels/hexdump.hpp deleted file mode 100644 index bd26884..0000000 --- a/extensions/openpower-pels/hexdump.hpp +++ /dev/null @@ -1,33 +0,0 @@ -#pragma once - -#include -#include - -#include -#include -#include -#include -#include - -namespace openpower -{ -namespace pels -{ - -/** - * @brief escape json - use it for PEL hex dumps. - * @param[in] std::string - the unescaped JSON as a string literal - * @return std::string - escaped JSON string literal - */ -std::string escapeJSON(const std::string& input); - -/** - * @brief get hex dump for PEL section in json format. - * @param[in] const void* - Raw PEL data - * @param[i] size_t - size of Raw PEL - * @return char * - the Hex dump - */ -char* dumpHex(const void* data, size_t size); - -} // namespace pels -} // namespace openpower diff --git a/extensions/openpower-pels/json_utils.cpp b/extensions/openpower-pels/json_utils.cpp new file mode 100644 index 0000000..c6ea9f6 --- /dev/null +++ b/extensions/openpower-pels/json_utils.cpp @@ -0,0 +1,197 @@ +/** + * Copyright © 2019 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 "json_utils.hpp" + +#include + +#include +#include +#include + +namespace openpower +{ +namespace pels +{ + +std::string escapeJSON(const std::string& input) +{ + std::string output; + output.reserve(input.length()); + + for (const auto c : input) + { + switch (c) + { + case '"': + output += "\\\""; + break; + case '/': + output += "\\/"; + break; + case '\b': + output += "\\b"; + break; + case '\f': + output += "\\f"; + break; + case '\n': + output += "\\n"; + break; + case '\r': + output += "\\r"; + break; + case '\t': + output += "\\t"; + break; + case '\\': + output += "\\\\"; + break; + default: + output += c; + break; + } + } + + return output; +} +char* dumpHex(const void* data, size_t size) +{ + const int symbolSize = 100; + std::string jsonIndent(indentLevel, 0x20); + jsonIndent.append("\""); + char* buffer = (char*)calloc(10 * size, sizeof(char)); + char* symbol = (char*)calloc(symbolSize, sizeof(char)); + char ascii[17]; + size_t i, j; + ascii[16] = '\0'; + for (i = 0; i < size; ++i) + { + if (i % 16 == 0) + { + strcat(buffer, jsonIndent.c_str()); + } + snprintf(symbol, symbolSize, "%02X ", ((unsigned char*)data)[i]); + strcat(buffer, symbol); + memset(symbol, 0, strlen(symbol)); + if (((unsigned char*)data)[i] >= ' ' && + ((unsigned char*)data)[i] <= '~') + { + ascii[i % 16] = ((unsigned char*)data)[i]; + } + else + { + ascii[i % 16] = '.'; + } + if ((i + 1) % 8 == 0 || i + 1 == size) + { + std::string asciiString(ascii); + asciiString = escapeJSON(asciiString); + const char* asciiToPrint = asciiString.c_str(); + strcat(buffer, " "); + if ((i + 1) % 16 == 0) + { + if (i + 1 != size) + { + snprintf(symbol, symbolSize, "| %s\",\n", asciiToPrint); + } + else + { + snprintf(symbol, symbolSize, "| %s\"\n", asciiToPrint); + } + strcat(buffer, symbol); + memset(symbol, 0, strlen(symbol)); + } + else if (i + 1 == size) + { + ascii[(i + 1) % 16] = '\0'; + if ((i + 1) % 16 <= 8) + { + strcat(buffer, " "); + } + for (j = (i + 1) % 16; j < 16; ++j) + { + strcat(buffer, " "); + } + std::string asciiString2(ascii); + asciiString2 = escapeJSON(asciiString2); + asciiToPrint = asciiString2.c_str(); + snprintf(symbol, symbolSize, "| %s\"\n", asciiToPrint); + strcat(buffer, symbol); + memset(symbol, 0, strlen(symbol)); + } + } + } + free(symbol); + return buffer; +} + +void jsonInsert(std::string& jsonStr, const std::string& fieldName, + std::string& fieldValue, uint8_t indentCount) +{ + const int8_t spacesToAppend = + colAlign - (indentCount * indentLevel) - fieldName.length() - 3; + const std::string jsonIndent(indentCount * indentLevel, 0x20); + jsonStr.append(jsonIndent + "\"" + fieldName + "\":"); + if (spacesToAppend > 0) + { + jsonStr.append(spacesToAppend, 0x20); + } + else + { + jsonStr.append(1, 0x20); + } + jsonStr.append("\"" + fieldValue + "\",\n"); +} + +void jsonInsertArray(std::string& jsonStr, const std::string& fieldName, + std::vector& values, uint8_t indentCount) +{ + const std::string jsonIndent(indentCount * indentLevel, 0x20); + if (!values.empty()) + { + jsonStr.append(jsonIndent + "\"" + fieldName + "\": [\n"); + for (size_t i = 0; i < values.size(); i++) + { + jsonStr.append(colAlign, 0x20); + if (i == values.size() - 1) + { + jsonStr.append("\"" + values[i] + "\"\n"); + } + else + { + jsonStr.append("\"" + values[i] + "\",\n"); + } + } + jsonStr.append(jsonIndent + "],\n"); + } + else + { + const int8_t spacesToAppend = + colAlign - (indentCount * indentLevel) - fieldName.length() - 3; + jsonStr.append(jsonIndent + "\"" + fieldName + "\":"); + if (spacesToAppend > 0) + { + jsonStr.append(spacesToAppend, 0x20); + } + else + { + jsonStr.append(1, 0x20); + } + jsonStr.append("[],\n"); + } +} +} // namespace pels +} // namespace openpower diff --git a/extensions/openpower-pels/json_utils.hpp b/extensions/openpower-pels/json_utils.hpp new file mode 100644 index 0000000..14c2ce4 --- /dev/null +++ b/extensions/openpower-pels/json_utils.hpp @@ -0,0 +1,55 @@ +#pragma once + +#include +#include + +#include +#include +#include +#include +#include + +namespace openpower +{ +namespace pels +{ +const uint8_t indentLevel = 4; +const uint8_t colAlign = 32; +/** + * @brief escape json - use it for PEL hex dumps. + * @param[in] std::string - the unescaped JSON as a string literal + * @return std::string - escaped JSON string literal + */ +std::string escapeJSON(const std::string& input); + +/** + * @brief get hex dump for PEL section in json format. + * @param[in] const void* - Raw PEL data + * @param[i] size_t - size of Raw PEL + * @return char * - the Hex dump + */ +char* dumpHex(const void* data, size_t size); + +/** + * @brief Inserts key-value into a JSON string + * + * @param[in] jsonStr - The JSON string + * @param[in] fieldName - The JSON key to insert + * @param[in] fieldValue - The JSON value to insert + * @param[in] indentCount - Indent count for the line + */ +void jsonInsert(std::string& jsonStr, const std::string& fieldName, + std::string& fieldValue, uint8_t indentCount); + +/** + * @brief Inserts key-value array into a JSON string + * + * @param[in] jsonStr - The JSON string + * @param[in] fieldName - The JSON key to insert + * @param[in] values - The JSON array to insert + * @param[in] indentCount - Indent count for the line + */ +void jsonInsertArray(std::string& jsonStr, const std::string& fieldName, + std::vector& values, uint8_t indentCount); +} // namespace pels +} // namespace openpower diff --git a/extensions/openpower-pels/openpower-pels.mk b/extensions/openpower-pels/openpower-pels.mk index 5bce70d..d974e06 100644 --- a/extensions/openpower-pels/openpower-pels.mk +++ b/extensions/openpower-pels/openpower-pels.mk @@ -18,7 +18,7 @@ libpel_la_SOURCES = \ extensions/openpower-pels/failing_mtms.cpp \ extensions/openpower-pels/fru_identity.cpp \ extensions/openpower-pels/generic.cpp \ - extensions/openpower-pels/hexdump.cpp \ + extensions/openpower-pels/json_utils.cpp \ extensions/openpower-pels/log_id.cpp \ extensions/openpower-pels/mru.cpp \ extensions/openpower-pels/mtms.cpp \ diff --git a/extensions/openpower-pels/pel.cpp b/extensions/openpower-pels/pel.cpp index 022ac05..74d46bd 100644 --- a/extensions/openpower-pels/pel.cpp +++ b/extensions/openpower-pels/pel.cpp @@ -18,7 +18,7 @@ #include "bcd_time.hpp" #include "extended_user_header.hpp" #include "failing_mtms.hpp" -#include "hexdump.hpp" +#include "json_utils.hpp" #include "log_id.hpp" #include "pel_rules.hpp" #include "pel_values.hpp" @@ -229,12 +229,12 @@ void PEL::printSectionInJSON(const Section& section, std::string& buf) const auto json = section.getJSON(); if (json) { - buf += "\n\"" + sectionName + "\":[\n "; - buf += *json + "\n],\n"; + buf += "\n\"" + sectionName + "\": {\n"; + buf += *json + "\n},\n"; } else { - buf += "\n\"" + sectionName + "\":[\n "; + buf += "\n\"" + sectionName + "\": [\n"; std::vector data; Stream s{data}; section.flatten(s); @@ -244,7 +244,7 @@ void PEL::printSectionInJSON(const Section& section, std::string& buf) const } else { - buf += "\n\"Invalid Section \":[\n invalid \n],\n"; + buf += "\n\"Invalid Section\": [\n \"invalid\"\n],\n"; } } @@ -263,5 +263,6 @@ void PEL::toJSON() const buf.replace(found, 1, ""); std::cout << buf << std::endl; } + } // namespace pels } // namespace openpower diff --git a/extensions/openpower-pels/pel_values.cpp b/extensions/openpower-pels/pel_values.cpp index 3502f92..f8c877c 100644 --- a/extensions/openpower-pels/pel_values.cpp +++ b/extensions/openpower-pels/pel_values.cpp @@ -196,8 +196,10 @@ const PELValues actionFlagsValues = { {0x8000, "service_action", "Service Action Required"}, {0x4000, "hidden", "Event not customer viewable"}, {0x2000, "report", "Report Externally"}, - {0x1000, "dont_report", "Do Not Report"}, + {0x1000, "dont_report", "Do Not Report To Hypervisor"}, {0x0800, "call_home", "HMC Call Home"}, + {0x0400, "isolation_incomplete", + "Isolation Incomplete, further analysis required"}, {0x0100, "termination", "Service Processor Call Home Required"}}; /** @@ -276,6 +278,20 @@ std::string getValue(const uint8_t field, const pel_values::PELValues& values) return "invalid"; } } + +std::vector getValuesBitwise(uint16_t value, + const pel_values::PELValues& table) +{ + std::vector foundValues; + std::for_each( + table.begin(), table.end(), [&value, &foundValues](const auto& entry) { + if (value & std::get(entry)) + { + foundValues.push_back(std::get(entry)); + } + }); + return foundValues; +} } // namespace pel_values } // namespace pels } // namespace openpower diff --git a/extensions/openpower-pels/pel_values.hpp b/extensions/openpower-pels/pel_values.hpp index 8d86acf..9a1ed88 100644 --- a/extensions/openpower-pels/pel_values.hpp +++ b/extensions/openpower-pels/pel_values.hpp @@ -32,6 +32,16 @@ using PELValues = std::vector; */ std::string getValue(const uint8_t field, const pel_values::PELValues& values); +/** + * @brief Helper function to get value vector from lookup tables. + * + * @param[in] value - the value to lookup + * @param[in] table - lookup table + * + * @return std::vector - the value vector + */ +std::vector getValuesBitwise(uint16_t value, + const pel_values::PELValues& table); /** * @brief Find the desired entry in a PELValues table based on the * field value. diff --git a/extensions/openpower-pels/user_header.cpp b/extensions/openpower-pels/user_header.cpp index 5aef28d..b70da94 100644 --- a/extensions/openpower-pels/user_header.cpp +++ b/extensions/openpower-pels/user_header.cpp @@ -15,6 +15,7 @@ */ #include "user_header.hpp" +#include "json_utils.hpp" #include "pel_types.hpp" #include "pel_values.hpp" #include "severity.hpp" @@ -135,10 +136,13 @@ std::optional UserHeader::getJSON() const std::string subsystem; std::string eventScope; std::string eventType; + std::vector actionFlags; severity = pv::getValue(_eventSeverity, pel_values::severityValues); subsystem = pv::getValue(_eventSubsystem, pel_values::subsystemValues); eventScope = pv::getValue(_eventScope, pel_values::eventScopeValues); eventType = pv::getValue(_eventType, pel_values::eventTypeValues); + actionFlags = + pv::getValuesBitwise(_actionFlags, pel_values::actionFlagsValues); char tmpUhVal[8]; sprintf(tmpUhVal, "%d", userHeaderVersion); std::string uhVerStr(tmpUhVal); @@ -147,15 +151,16 @@ std::optional UserHeader::getJSON() const sprintf(tmpUhVal, "%d", _header.subType); std::string uhStStr(tmpUhVal); - std::string uh = "{\"Section Version\": \"" + uhVerStr + - "\"}, \n {\"Sub-section type\": \"" + uhStStr + - "\"}, \n " - "{\"Log Committed by\": \"" + - uhCbStr + "\"}, \n {\"Subsystem\": \"" + subsystem + - "\"},\n " - "{\"Event Scope\": \"" + - eventScope + "\"}, \n {\"Event Severity\":\"" + severity + - "\"},\n {\"Event Type\": \"" + eventType + "\"}"; + std::string uh; + jsonInsert(uh, "Section Version", uhVerStr, 1); + jsonInsert(uh, "Sub-section type", uhStStr, 1); + jsonInsert(uh, "Log Committed by", uhCbStr, 1); + jsonInsert(uh, "Subsystem", subsystem, 1); + jsonInsert(uh, "Event Scope", eventScope, 1); + jsonInsert(uh, "Event Severity", severity, 1); + jsonInsert(uh, "Event Type", eventType, 1); + jsonInsertArray(uh, "Action Flags", actionFlags, 1); + uh.erase(uh.size() - 2); return uh; } } // namespace pels diff --git a/test/openpower-pels/Makefile.include b/test/openpower-pels/Makefile.include index dfa4156..d85f215 100644 --- a/test/openpower-pels/Makefile.include +++ b/test/openpower-pels/Makefile.include @@ -38,7 +38,7 @@ pel_objects = \ $(top_builddir)/extensions/openpower-pels/failing_mtms.o \ $(top_builddir)/extensions/openpower-pels/fru_identity.o \ $(top_builddir)/extensions/openpower-pels/generic.o \ - $(top_builddir)/extensions/openpower-pels/hexdump.o \ + $(top_builddir)/extensions/openpower-pels/json_utils.o \ $(top_builddir)/extensions/openpower-pels/log_id.o \ $(top_builddir)/extensions/openpower-pels/mtms.o \ $(top_builddir)/extensions/openpower-pels/mru.o \ -- cgit v1.2.3