| Matt Spinler | 711d51d | 2019-11-06 09:36:51 -0600 | [diff] [blame] | 1 | /** | 
|  | 2 | * Copyright © 2019 IBM Corporation | 
|  | 3 | * | 
|  | 4 | * Licensed under the Apache License, Version 2.0 (the "License"); | 
|  | 5 | * you may not use this file except in compliance with the License. | 
|  | 6 | * You may obtain a copy of the License at | 
|  | 7 | * | 
|  | 8 | *     http://www.apache.org/licenses/LICENSE-2.0 | 
|  | 9 | * | 
|  | 10 | * Unless required by applicable law or agreed to in writing, software | 
|  | 11 | * distributed under the License is distributed on an "AS IS" BASIS, | 
|  | 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 
|  | 13 | * See the License for the specific language governing permissions and | 
|  | 14 | * limitations under the License. | 
|  | 15 | */ | 
| Jayanth Othayoth | da9b583 | 2021-11-05 04:19:43 -0500 | [diff] [blame] | 16 | #include "config.h" | 
|  | 17 |  | 
| Matt Spinler | cb6b059 | 2019-07-16 15:58:51 -0500 | [diff] [blame] | 18 | #include "pel.hpp" | 
|  | 19 |  | 
|  | 20 | #include "bcd_time.hpp" | 
| Matt Spinler | 386a61e | 2020-08-13 15:51:12 -0500 | [diff] [blame] | 21 | #include "extended_user_data.hpp" | 
| Matt Spinler | c63e2e8 | 2019-12-02 15:50:12 -0600 | [diff] [blame] | 22 | #include "extended_user_header.hpp" | 
| Matt Spinler | aa65947 | 2019-10-23 09:26:48 -0500 | [diff] [blame] | 23 | #include "failing_mtms.hpp" | 
| Andrew Geissler | f8e750d | 2022-01-14 14:56:13 -0600 | [diff] [blame] | 24 | #include "fru_identity.hpp" | 
| Harisuddin Mohamed Isa | 600d15a | 2019-12-20 12:42:26 +0800 | [diff] [blame] | 25 | #include "json_utils.hpp" | 
| Matt Spinler | cb6b059 | 2019-07-16 15:58:51 -0500 | [diff] [blame] | 26 | #include "log_id.hpp" | 
| Matt Spinler | f1e85e2 | 2019-11-01 11:31:31 -0500 | [diff] [blame] | 27 | #include "pel_rules.hpp" | 
| Aatir | 186ce8c | 2019-10-20 15:13:39 -0500 | [diff] [blame] | 28 | #include "pel_values.hpp" | 
| Matt Spinler | 131870c | 2019-09-25 13:29:04 -0500 | [diff] [blame] | 29 | #include "section_factory.hpp" | 
| Matt Spinler | bd716f0 | 2019-10-15 10:54:11 -0500 | [diff] [blame] | 30 | #include "src.hpp" | 
| Matt Spinler | cb6b059 | 2019-07-16 15:58:51 -0500 | [diff] [blame] | 31 | #include "stream.hpp" | 
| Matt Spinler | afa857c | 2019-10-24 13:03:46 -0500 | [diff] [blame] | 32 | #include "user_data_formats.hpp" | 
| Matt Spinler | cb6b059 | 2019-07-16 15:58:51 -0500 | [diff] [blame] | 33 |  | 
| Jayanth Othayoth | 92b2066 | 2021-11-05 00:09:15 -0500 | [diff] [blame] | 34 | #ifdef PEL_ENABLE_PHAL | 
| Jayanth Othayoth | da9b583 | 2021-11-05 04:19:43 -0500 | [diff] [blame] | 35 | #include "phal_service_actions.hpp" | 
| Jayanth Othayoth | e8bdeea | 2021-06-03 03:01:16 -0500 | [diff] [blame] | 36 | #include "sbe_ffdc_handler.hpp" | 
|  | 37 | #endif | 
|  | 38 |  | 
| Ben Tyner | e32b7e7 | 2021-05-18 12:38:40 -0500 | [diff] [blame] | 39 | #include <fmt/format.h> | 
| Matt Spinler | 5b289b2 | 2020-03-26 14:27:19 -0500 | [diff] [blame] | 40 | #include <sys/stat.h> | 
|  | 41 | #include <unistd.h> | 
|  | 42 |  | 
| Aatir | 186ce8c | 2019-10-20 15:13:39 -0500 | [diff] [blame] | 43 | #include <iostream> | 
| Matt Spinler | 07eefc5 | 2019-09-26 11:18:26 -0500 | [diff] [blame] | 44 | #include <phosphor-logging/log.hpp> | 
|  | 45 |  | 
| Matt Spinler | cb6b059 | 2019-07-16 15:58:51 -0500 | [diff] [blame] | 46 | namespace openpower | 
|  | 47 | { | 
|  | 48 | namespace pels | 
|  | 49 | { | 
| Matt Spinler | b832363 | 2019-09-20 15:11:04 -0500 | [diff] [blame] | 50 | namespace message = openpower::pels::message; | 
| Aatir | 186ce8c | 2019-10-20 15:13:39 -0500 | [diff] [blame] | 51 | namespace pv = openpower::pels::pel_values; | 
| Matt Spinler | 4bfc908 | 2020-03-24 15:05:54 -0500 | [diff] [blame] | 52 | using namespace phosphor::logging; | 
| Matt Spinler | b832363 | 2019-09-20 15:11:04 -0500 | [diff] [blame] | 53 |  | 
| Matt Spinler | 677381b | 2020-01-23 10:04:29 -0600 | [diff] [blame] | 54 | constexpr auto unknownValue = "Unknown"; | 
|  | 55 |  | 
| Matt Spinler | 4bfc908 | 2020-03-24 15:05:54 -0500 | [diff] [blame] | 56 | PEL::PEL(const message::Entry& regEntry, uint32_t obmcLogID, uint64_t timestamp, | 
| Matt Spinler | bd716f0 | 2019-10-15 10:54:11 -0500 | [diff] [blame] | 57 | phosphor::logging::Entry::Level severity, | 
| Jayanth Othayoth | e8bdeea | 2021-06-03 03:01:16 -0500 | [diff] [blame] | 58 | const AdditionalData& additionalData, const PelFFDC& ffdcFilesIn, | 
| Matt Spinler | aa65947 | 2019-10-23 09:26:48 -0500 | [diff] [blame] | 59 | const DataInterfaceBase& dataIface) | 
| Matt Spinler | b832363 | 2019-09-20 15:11:04 -0500 | [diff] [blame] | 60 | { | 
| Jayanth Othayoth | e8bdeea | 2021-06-03 03:01:16 -0500 | [diff] [blame] | 61 | // No changes in input, for non SBE error related requests | 
|  | 62 | PelFFDC ffdcFiles = ffdcFilesIn; | 
|  | 63 |  | 
| Jayanth Othayoth | 92b2066 | 2021-11-05 00:09:15 -0500 | [diff] [blame] | 64 | #ifdef PEL_ENABLE_PHAL | 
| Jayanth Othayoth | e8bdeea | 2021-06-03 03:01:16 -0500 | [diff] [blame] | 65 | // Add sbe ffdc processed data into ffdcfiles. | 
|  | 66 | namespace sbe = openpower::pels::sbe; | 
|  | 67 | auto processReq = | 
|  | 68 | std::any_of(ffdcFiles.begin(), ffdcFiles.end(), [](const auto& file) { | 
|  | 69 | return file.format == UserDataFormat::custom && | 
|  | 70 | file.subType == sbe::sbeFFDCSubType; | 
|  | 71 | }); | 
|  | 72 | // sbeFFDC can't be destroyed until the end of the PEL constructor | 
|  | 73 | // because it needs to keep around the FFDC Files to be used below. | 
|  | 74 | std::unique_ptr<sbe::SbeFFDC> sbeFFDCPtr; | 
|  | 75 | if (processReq) | 
|  | 76 | { | 
|  | 77 | sbeFFDCPtr = | 
|  | 78 | std::make_unique<sbe::SbeFFDC>(additionalData, ffdcFilesIn); | 
|  | 79 | const auto& sbeFFDCFiles = sbeFFDCPtr->getSbeFFDC(); | 
|  | 80 | ffdcFiles.insert(ffdcFiles.end(), sbeFFDCFiles.begin(), | 
|  | 81 | sbeFFDCFiles.end()); | 
|  | 82 | } | 
|  | 83 | #endif | 
|  | 84 |  | 
| Matt Spinler | 85f61a6 | 2020-06-03 16:28:55 -0500 | [diff] [blame] | 85 | std::map<std::string, std::vector<std::string>> debugData; | 
| Matt Spinler | 5a90a95 | 2020-08-27 09:39:03 -0500 | [diff] [blame] | 86 | nlohmann::json callouts; | 
| Matt Spinler | 85f61a6 | 2020-06-03 16:28:55 -0500 | [diff] [blame] | 87 |  | 
| Matt Spinler | 4bfc908 | 2020-03-24 15:05:54 -0500 | [diff] [blame] | 88 | _ph = std::make_unique<PrivateHeader>(regEntry.componentID, obmcLogID, | 
| Matt Spinler | b832363 | 2019-09-20 15:11:04 -0500 | [diff] [blame] | 89 | timestamp); | 
| Vijay Lobo | 6b3f345 | 2021-04-15 23:04:42 -0500 | [diff] [blame] | 90 | _uh = std::make_unique<UserHeader>(regEntry, severity, additionalData, | 
|  | 91 | dataIface); | 
| Matt Spinler | b832363 | 2019-09-20 15:11:04 -0500 | [diff] [blame] | 92 |  | 
| Matt Spinler | 5a90a95 | 2020-08-27 09:39:03 -0500 | [diff] [blame] | 93 | // Extract any callouts embedded in an FFDC file. | 
|  | 94 | if (!ffdcFiles.empty()) | 
|  | 95 | { | 
|  | 96 | try | 
|  | 97 | { | 
|  | 98 | callouts = getCalloutJSON(ffdcFiles); | 
|  | 99 | } | 
|  | 100 | catch (const std::exception& e) | 
|  | 101 | { | 
|  | 102 | debugData.emplace("FFDC file JSON callouts error", | 
|  | 103 | std::vector<std::string>{e.what()}); | 
|  | 104 | } | 
|  | 105 | } | 
|  | 106 |  | 
|  | 107 | auto src = | 
|  | 108 | std::make_unique<SRC>(regEntry, additionalData, callouts, dataIface); | 
|  | 109 |  | 
| Matt Spinler | 85f61a6 | 2020-06-03 16:28:55 -0500 | [diff] [blame] | 110 | if (!src->getDebugData().empty()) | 
|  | 111 | { | 
|  | 112 | // Something didn't go as planned | 
|  | 113 | debugData.emplace("SRC", src->getDebugData()); | 
|  | 114 | } | 
| Matt Spinler | c63e2e8 | 2019-12-02 15:50:12 -0600 | [diff] [blame] | 115 |  | 
| Matt Spinler | 4bfc908 | 2020-03-24 15:05:54 -0500 | [diff] [blame] | 116 | auto euh = std::make_unique<ExtendedUserHeader>(dataIface, regEntry, *src); | 
| Matt Spinler | c63e2e8 | 2019-12-02 15:50:12 -0600 | [diff] [blame] | 117 |  | 
| Matt Spinler | bd716f0 | 2019-10-15 10:54:11 -0500 | [diff] [blame] | 118 | _optionalSections.push_back(std::move(src)); | 
| Matt Spinler | c63e2e8 | 2019-12-02 15:50:12 -0600 | [diff] [blame] | 119 | _optionalSections.push_back(std::move(euh)); | 
| Matt Spinler | b832363 | 2019-09-20 15:11:04 -0500 | [diff] [blame] | 120 |  | 
| Matt Spinler | aa65947 | 2019-10-23 09:26:48 -0500 | [diff] [blame] | 121 | auto mtms = std::make_unique<FailingMTMS>(dataIface); | 
|  | 122 | _optionalSections.push_back(std::move(mtms)); | 
| Matt Spinler | bd716f0 | 2019-10-15 10:54:11 -0500 | [diff] [blame] | 123 |  | 
| Matt Spinler | 4dcd3f4 | 2020-01-22 14:55:07 -0600 | [diff] [blame] | 124 | auto ud = util::makeSysInfoUserDataSection(additionalData, dataIface); | 
| Matt Spinler | 85f61a6 | 2020-06-03 16:28:55 -0500 | [diff] [blame] | 125 | addUserDataSection(std::move(ud)); | 
| Matt Spinler | 4dcd3f4 | 2020-01-22 14:55:07 -0600 | [diff] [blame] | 126 |  | 
| Sumit Kumar | 3e27443 | 2021-09-14 06:37:56 -0500 | [diff] [blame] | 127 | //  Check for pel severity of type - 0x51 = critical error, system | 
|  | 128 | //  termination and update terminate bit in SRC for pels | 
|  | 129 | updateTerminateBitInSRCSection(); | 
|  | 130 |  | 
| Matt Spinler | 9b7e94f | 2020-03-24 15:44:41 -0500 | [diff] [blame] | 131 | // Create a UserData section from AdditionalData. | 
| Matt Spinler | afa857c | 2019-10-24 13:03:46 -0500 | [diff] [blame] | 132 | if (!additionalData.empty()) | 
|  | 133 | { | 
| Matt Spinler | 4dcd3f4 | 2020-01-22 14:55:07 -0600 | [diff] [blame] | 134 | ud = util::makeADUserDataSection(additionalData); | 
| Matt Spinler | 85f61a6 | 2020-06-03 16:28:55 -0500 | [diff] [blame] | 135 | addUserDataSection(std::move(ud)); | 
| Matt Spinler | afa857c | 2019-10-24 13:03:46 -0500 | [diff] [blame] | 136 | } | 
|  | 137 |  | 
| Matt Spinler | 56ad2a0 | 2020-03-26 14:00:52 -0500 | [diff] [blame] | 138 | // Add any FFDC files into UserData sections | 
|  | 139 | for (const auto& file : ffdcFiles) | 
|  | 140 | { | 
|  | 141 | ud = util::makeFFDCuserDataSection(regEntry.componentID, file); | 
|  | 142 | if (!ud) | 
|  | 143 | { | 
| Matt Spinler | 85f61a6 | 2020-06-03 16:28:55 -0500 | [diff] [blame] | 144 | // Add this error into the debug data UserData section | 
|  | 145 | std::ostringstream msg; | 
|  | 146 | msg << "Could not make PEL FFDC UserData section from file" | 
|  | 147 | << std::hex << regEntry.componentID << " " << file.subType | 
|  | 148 | << " " << file.version; | 
|  | 149 | if (debugData.count("FFDC File")) | 
|  | 150 | { | 
|  | 151 | debugData.at("FFDC File").push_back(msg.str()); | 
|  | 152 | } | 
|  | 153 | else | 
|  | 154 | { | 
|  | 155 | debugData.emplace("FFDC File", | 
|  | 156 | std::vector<std::string>{msg.str()}); | 
|  | 157 | } | 
|  | 158 |  | 
| Matt Spinler | 56ad2a0 | 2020-03-26 14:00:52 -0500 | [diff] [blame] | 159 | continue; | 
|  | 160 | } | 
|  | 161 |  | 
| Matt Spinler | 85f61a6 | 2020-06-03 16:28:55 -0500 | [diff] [blame] | 162 | addUserDataSection(std::move(ud)); | 
|  | 163 | } | 
| Matt Spinler | 56ad2a0 | 2020-03-26 14:00:52 -0500 | [diff] [blame] | 164 |  | 
| Jayanth Othayoth | da9b583 | 2021-11-05 04:19:43 -0500 | [diff] [blame] | 165 | #ifdef PEL_ENABLE_PHAL | 
|  | 166 | auto path = std::string(OBJ_ENTRY) + '/' + std::to_string(obmcLogID); | 
| Jayanth Othayoth | 3ef7b60 | 2021-11-09 06:40:38 -0600 | [diff] [blame] | 167 | openpower::pels::phal::createServiceActions(callouts, path, dataIface, | 
|  | 168 | plid()); | 
| Jayanth Othayoth | da9b583 | 2021-11-05 04:19:43 -0500 | [diff] [blame] | 169 | #endif | 
|  | 170 |  | 
| Matt Spinler | 85f61a6 | 2020-06-03 16:28:55 -0500 | [diff] [blame] | 171 | // Store in the PEL any important debug data created while | 
|  | 172 | // building the PEL sections. | 
|  | 173 | if (!debugData.empty()) | 
|  | 174 | { | 
|  | 175 | nlohmann::json data; | 
|  | 176 | data["PEL Internal Debug Data"] = debugData; | 
|  | 177 | ud = util::makeJSONUserDataSection(data); | 
|  | 178 |  | 
|  | 179 | addUserDataSection(std::move(ud)); | 
|  | 180 |  | 
|  | 181 | // Also put in the journal for debug | 
|  | 182 | for (const auto& [name, data] : debugData) | 
|  | 183 | { | 
|  | 184 | for (const auto& message : data) | 
|  | 185 | { | 
|  | 186 | std::string entry = name + ": " + message; | 
|  | 187 | log<level::INFO>(entry.c_str()); | 
| Matt Spinler | 56ad2a0 | 2020-03-26 14:00:52 -0500 | [diff] [blame] | 188 | } | 
|  | 189 | } | 
| Matt Spinler | 56ad2a0 | 2020-03-26 14:00:52 -0500 | [diff] [blame] | 190 | } | 
|  | 191 |  | 
| Matt Spinler | 97d19b4 | 2019-10-29 11:34:03 -0500 | [diff] [blame] | 192 | _ph->setSectionCount(2 + _optionalSections.size()); | 
| Matt Spinler | f1e85e2 | 2019-11-01 11:31:31 -0500 | [diff] [blame] | 193 |  | 
|  | 194 | checkRulesAndFix(); | 
| Matt Spinler | b832363 | 2019-09-20 15:11:04 -0500 | [diff] [blame] | 195 | } | 
| Matt Spinler | cb6b059 | 2019-07-16 15:58:51 -0500 | [diff] [blame] | 196 |  | 
| Matt Spinler | 07eefc5 | 2019-09-26 11:18:26 -0500 | [diff] [blame] | 197 | PEL::PEL(std::vector<uint8_t>& data) : PEL(data, 0) | 
| Matt Spinler | cb6b059 | 2019-07-16 15:58:51 -0500 | [diff] [blame] | 198 | { | 
|  | 199 | } | 
|  | 200 |  | 
| Matt Spinler | 07eefc5 | 2019-09-26 11:18:26 -0500 | [diff] [blame] | 201 | PEL::PEL(std::vector<uint8_t>& data, uint32_t obmcLogID) | 
| Matt Spinler | cb6b059 | 2019-07-16 15:58:51 -0500 | [diff] [blame] | 202 | { | 
| Matt Spinler | 07eefc5 | 2019-09-26 11:18:26 -0500 | [diff] [blame] | 203 | populateFromRawData(data, obmcLogID); | 
| Matt Spinler | cb6b059 | 2019-07-16 15:58:51 -0500 | [diff] [blame] | 204 | } | 
|  | 205 |  | 
| Matt Spinler | 07eefc5 | 2019-09-26 11:18:26 -0500 | [diff] [blame] | 206 | void PEL::populateFromRawData(std::vector<uint8_t>& data, uint32_t obmcLogID) | 
| Matt Spinler | cb6b059 | 2019-07-16 15:58:51 -0500 | [diff] [blame] | 207 | { | 
| Matt Spinler | 07eefc5 | 2019-09-26 11:18:26 -0500 | [diff] [blame] | 208 | Stream pelData{data}; | 
| Matt Spinler | cb6b059 | 2019-07-16 15:58:51 -0500 | [diff] [blame] | 209 | _ph = std::make_unique<PrivateHeader>(pelData); | 
|  | 210 | if (obmcLogID != 0) | 
|  | 211 | { | 
| Matt Spinler | 97d19b4 | 2019-10-29 11:34:03 -0500 | [diff] [blame] | 212 | _ph->setOBMCLogID(obmcLogID); | 
| Matt Spinler | cb6b059 | 2019-07-16 15:58:51 -0500 | [diff] [blame] | 213 | } | 
|  | 214 |  | 
|  | 215 | _uh = std::make_unique<UserHeader>(pelData); | 
| Matt Spinler | 131870c | 2019-09-25 13:29:04 -0500 | [diff] [blame] | 216 |  | 
|  | 217 | // Use the section factory to create the rest of the objects | 
|  | 218 | for (size_t i = 2; i < _ph->sectionCount(); i++) | 
|  | 219 | { | 
|  | 220 | auto section = section_factory::create(pelData); | 
|  | 221 | _optionalSections.push_back(std::move(section)); | 
|  | 222 | } | 
| Matt Spinler | cb6b059 | 2019-07-16 15:58:51 -0500 | [diff] [blame] | 223 | } | 
|  | 224 |  | 
|  | 225 | bool PEL::valid() const | 
|  | 226 | { | 
|  | 227 | bool valid = _ph->valid(); | 
|  | 228 |  | 
|  | 229 | if (valid) | 
|  | 230 | { | 
|  | 231 | valid = _uh->valid(); | 
|  | 232 | } | 
|  | 233 |  | 
| Matt Spinler | 131870c | 2019-09-25 13:29:04 -0500 | [diff] [blame] | 234 | if (valid) | 
|  | 235 | { | 
|  | 236 | if (!std::all_of(_optionalSections.begin(), _optionalSections.end(), | 
|  | 237 | [](const auto& section) { return section->valid(); })) | 
|  | 238 | { | 
|  | 239 | valid = false; | 
|  | 240 | } | 
|  | 241 | } | 
|  | 242 |  | 
| Matt Spinler | cb6b059 | 2019-07-16 15:58:51 -0500 | [diff] [blame] | 243 | return valid; | 
|  | 244 | } | 
|  | 245 |  | 
|  | 246 | void PEL::setCommitTime() | 
|  | 247 | { | 
|  | 248 | auto now = std::chrono::system_clock::now(); | 
| Matt Spinler | 97d19b4 | 2019-10-29 11:34:03 -0500 | [diff] [blame] | 249 | _ph->setCommitTimestamp(getBCDTime(now)); | 
| Matt Spinler | cb6b059 | 2019-07-16 15:58:51 -0500 | [diff] [blame] | 250 | } | 
|  | 251 |  | 
|  | 252 | void PEL::assignID() | 
|  | 253 | { | 
| Matt Spinler | 97d19b4 | 2019-10-29 11:34:03 -0500 | [diff] [blame] | 254 | _ph->setID(generatePELID()); | 
| Matt Spinler | cb6b059 | 2019-07-16 15:58:51 -0500 | [diff] [blame] | 255 | } | 
|  | 256 |  | 
| Matt Spinler | 0688545 | 2019-11-06 10:35:42 -0600 | [diff] [blame] | 257 | void PEL::flatten(std::vector<uint8_t>& pelBuffer) const | 
| Matt Spinler | cb6b059 | 2019-07-16 15:58:51 -0500 | [diff] [blame] | 258 | { | 
|  | 259 | Stream pelData{pelBuffer}; | 
| Matt Spinler | b832363 | 2019-09-20 15:11:04 -0500 | [diff] [blame] | 260 |  | 
| Matt Spinler | 07eefc5 | 2019-09-26 11:18:26 -0500 | [diff] [blame] | 261 | if (!valid()) | 
| Matt Spinler | cb6b059 | 2019-07-16 15:58:51 -0500 | [diff] [blame] | 262 | { | 
| Matt Spinler | 07eefc5 | 2019-09-26 11:18:26 -0500 | [diff] [blame] | 263 | log<level::WARNING>("Unflattening an invalid PEL"); | 
| Matt Spinler | cb6b059 | 2019-07-16 15:58:51 -0500 | [diff] [blame] | 264 | } | 
|  | 265 |  | 
| Matt Spinler | 07eefc5 | 2019-09-26 11:18:26 -0500 | [diff] [blame] | 266 | _ph->flatten(pelData); | 
| Matt Spinler | b832363 | 2019-09-20 15:11:04 -0500 | [diff] [blame] | 267 | _uh->flatten(pelData); | 
| Matt Spinler | 07eefc5 | 2019-09-26 11:18:26 -0500 | [diff] [blame] | 268 |  | 
|  | 269 | for (auto& section : _optionalSections) | 
|  | 270 | { | 
|  | 271 | section->flatten(pelData); | 
|  | 272 | } | 
| Matt Spinler | cb6b059 | 2019-07-16 15:58:51 -0500 | [diff] [blame] | 273 | } | 
|  | 274 |  | 
| Matt Spinler | 0688545 | 2019-11-06 10:35:42 -0600 | [diff] [blame] | 275 | std::vector<uint8_t> PEL::data() const | 
| Matt Spinler | cb6b059 | 2019-07-16 15:58:51 -0500 | [diff] [blame] | 276 | { | 
| Matt Spinler | 07eefc5 | 2019-09-26 11:18:26 -0500 | [diff] [blame] | 277 | std::vector<uint8_t> pelData; | 
|  | 278 | flatten(pelData); | 
|  | 279 | return pelData; | 
| Matt Spinler | cb6b059 | 2019-07-16 15:58:51 -0500 | [diff] [blame] | 280 | } | 
|  | 281 |  | 
| Matt Spinler | f1b46ff | 2020-01-22 14:10:04 -0600 | [diff] [blame] | 282 | size_t PEL::size() const | 
|  | 283 | { | 
|  | 284 | size_t size = 0; | 
|  | 285 |  | 
|  | 286 | if (_ph) | 
|  | 287 | { | 
|  | 288 | size += _ph->header().size; | 
|  | 289 | } | 
|  | 290 |  | 
|  | 291 | if (_uh) | 
|  | 292 | { | 
|  | 293 | size += _uh->header().size; | 
|  | 294 | } | 
|  | 295 |  | 
|  | 296 | for (const auto& section : _optionalSections) | 
|  | 297 | { | 
|  | 298 | size += section->header().size; | 
|  | 299 | } | 
|  | 300 |  | 
|  | 301 | return size; | 
|  | 302 | } | 
|  | 303 |  | 
| Matt Spinler | bd716f0 | 2019-10-15 10:54:11 -0500 | [diff] [blame] | 304 | std::optional<SRC*> PEL::primarySRC() const | 
|  | 305 | { | 
|  | 306 | auto src = std::find_if( | 
|  | 307 | _optionalSections.begin(), _optionalSections.end(), [](auto& section) { | 
|  | 308 | return section->header().id == | 
|  | 309 | static_cast<uint16_t>(SectionID::primarySRC); | 
|  | 310 | }); | 
|  | 311 | if (src != _optionalSections.end()) | 
|  | 312 | { | 
|  | 313 | return static_cast<SRC*>(src->get()); | 
|  | 314 | } | 
|  | 315 |  | 
|  | 316 | return std::nullopt; | 
|  | 317 | } | 
|  | 318 |  | 
| Matt Spinler | f1e85e2 | 2019-11-01 11:31:31 -0500 | [diff] [blame] | 319 | void PEL::checkRulesAndFix() | 
|  | 320 | { | 
| Matt Spinler | 1f93c59 | 2020-09-10 10:43:08 -0500 | [diff] [blame] | 321 | // Only fix if the action flags are at their default value which | 
|  | 322 | // means they weren't specified in the registry.  Otherwise | 
|  | 323 | // assume the user knows what they are doing. | 
|  | 324 | if (_uh->actionFlags() == actionFlagsDefault) | 
|  | 325 | { | 
|  | 326 | auto [actionFlags, eventType] = | 
|  | 327 | pel_rules::check(0, _uh->eventType(), _uh->severity()); | 
| Matt Spinler | f1e85e2 | 2019-11-01 11:31:31 -0500 | [diff] [blame] | 328 |  | 
| Matt Spinler | 1f93c59 | 2020-09-10 10:43:08 -0500 | [diff] [blame] | 329 | _uh->setActionFlags(actionFlags); | 
|  | 330 | _uh->setEventType(eventType); | 
|  | 331 | } | 
| Matt Spinler | f1e85e2 | 2019-11-01 11:31:31 -0500 | [diff] [blame] | 332 | } | 
|  | 333 |  | 
| Matt Spinler | acb7c10 | 2020-01-10 13:49:22 -0600 | [diff] [blame] | 334 | void PEL::printSectionInJSON(const Section& section, std::string& buf, | 
| Harisuddin Mohamed Isa | a214ed3 | 2020-02-28 15:58:23 +0800 | [diff] [blame] | 335 | std::map<uint16_t, size_t>& pluralSections, | 
| Harisuddin Mohamed Isa | f67bafd | 2020-07-06 17:51:21 +0800 | [diff] [blame] | 336 | message::Registry& registry, | 
|  | 337 | const std::vector<std::string>& plugins, | 
|  | 338 | uint8_t creatorID) const | 
| Aatir | 186ce8c | 2019-10-20 15:13:39 -0500 | [diff] [blame] | 339 | { | 
|  | 340 | char tmpB[5]; | 
| Aatir Manzur | ad0e047 | 2019-10-07 13:18:37 -0500 | [diff] [blame] | 341 | uint8_t id[] = {static_cast<uint8_t>(section.header().id >> 8), | 
|  | 342 | static_cast<uint8_t>(section.header().id)}; | 
|  | 343 | sprintf(tmpB, "%c%c", id[0], id[1]); | 
|  | 344 | std::string sectionID(tmpB); | 
|  | 345 | std::string sectionName = pv::sectionTitles.count(sectionID) | 
|  | 346 | ? pv::sectionTitles.at(sectionID) | 
|  | 347 | : "Unknown Section"; | 
| Matt Spinler | acb7c10 | 2020-01-10 13:49:22 -0600 | [diff] [blame] | 348 |  | 
|  | 349 | // Add a count if there are multiple of this type of section | 
|  | 350 | auto count = pluralSections.find(section.header().id); | 
|  | 351 | if (count != pluralSections.end()) | 
|  | 352 | { | 
|  | 353 | sectionName += " " + std::to_string(count->second); | 
|  | 354 | count->second++; | 
|  | 355 | } | 
|  | 356 |  | 
| Aatir | 186ce8c | 2019-10-20 15:13:39 -0500 | [diff] [blame] | 357 | if (section.valid()) | 
|  | 358 | { | 
| Harisuddin Mohamed Isa | f67bafd | 2020-07-06 17:51:21 +0800 | [diff] [blame] | 359 | std::optional<std::string> json; | 
|  | 360 | if (sectionID == "PS" || sectionID == "SS") | 
|  | 361 | { | 
| Harisuddin Mohamed Isa | c8d6cc6 | 2020-08-19 22:47:19 +0800 | [diff] [blame] | 362 | json = section.getJSON(registry, plugins, creatorID); | 
| Harisuddin Mohamed Isa | f67bafd | 2020-07-06 17:51:21 +0800 | [diff] [blame] | 363 | } | 
| Matt Spinler | 386a61e | 2020-08-13 15:51:12 -0500 | [diff] [blame] | 364 | else if ((sectionID == "UD") || (sectionID == "ED")) | 
| Harisuddin Mohamed Isa | f67bafd | 2020-07-06 17:51:21 +0800 | [diff] [blame] | 365 | { | 
| Harisuddin Mohamed Isa | 3fdcd4e | 2020-08-26 11:56:42 +0800 | [diff] [blame] | 366 | json = section.getJSON(creatorID, plugins); | 
| Harisuddin Mohamed Isa | f67bafd | 2020-07-06 17:51:21 +0800 | [diff] [blame] | 367 | } | 
|  | 368 | else | 
|  | 369 | { | 
|  | 370 | json = section.getJSON(); | 
|  | 371 | } | 
| Matt Spinler | 4220a15 | 2020-03-26 10:18:09 -0500 | [diff] [blame] | 372 |  | 
|  | 373 | buf += "\"" + sectionName + "\": {\n"; | 
|  | 374 |  | 
| Aatir Manzur | ad0e047 | 2019-10-07 13:18:37 -0500 | [diff] [blame] | 375 | if (json) | 
|  | 376 | { | 
| Harisuddin Mohamed Isa | 600d15a | 2019-12-20 12:42:26 +0800 | [diff] [blame] | 377 | buf += *json + "\n},\n"; | 
| Aatir Manzur | ad0e047 | 2019-10-07 13:18:37 -0500 | [diff] [blame] | 378 | } | 
|  | 379 | else | 
|  | 380 | { | 
| Matt Spinler | 4220a15 | 2020-03-26 10:18:09 -0500 | [diff] [blame] | 381 | jsonInsert(buf, pv::sectionVer, | 
|  | 382 | getNumberString("%d", section.header().version), 1); | 
|  | 383 | jsonInsert(buf, pv::subSection, | 
|  | 384 | getNumberString("%d", section.header().subType), 1); | 
|  | 385 | jsonInsert(buf, pv::createdBy, | 
|  | 386 | getNumberString("0x%X", section.header().componentID), | 
|  | 387 | 1); | 
|  | 388 |  | 
| Aatir Manzur | ad0e047 | 2019-10-07 13:18:37 -0500 | [diff] [blame] | 389 | std::vector<uint8_t> data; | 
|  | 390 | Stream s{data}; | 
|  | 391 | section.flatten(s); | 
| Matt Spinler | 4220a15 | 2020-03-26 10:18:09 -0500 | [diff] [blame] | 392 | std::string dstr = | 
|  | 393 | dumpHex(std::data(data) + SectionHeader::flattenedSize(), | 
| Harisuddin Mohamed Isa | 097ad12 | 2020-06-11 21:19:41 +0800 | [diff] [blame] | 394 | data.size() - SectionHeader::flattenedSize(), 2); | 
| Matt Spinler | 4220a15 | 2020-03-26 10:18:09 -0500 | [diff] [blame] | 395 | std::string jsonIndent(indentLevel, 0x20); | 
|  | 396 | buf += jsonIndent + "\"Data\": [\n"; | 
|  | 397 | buf += dstr; | 
|  | 398 | buf += jsonIndent + "]\n"; | 
|  | 399 | buf += "},\n"; | 
| Aatir Manzur | ad0e047 | 2019-10-07 13:18:37 -0500 | [diff] [blame] | 400 | } | 
| Aatir | 186ce8c | 2019-10-20 15:13:39 -0500 | [diff] [blame] | 401 | } | 
|  | 402 | else | 
|  | 403 | { | 
| Harisuddin Mohamed Isa | 600d15a | 2019-12-20 12:42:26 +0800 | [diff] [blame] | 404 | buf += "\n\"Invalid Section\": [\n    \"invalid\"\n],\n"; | 
| Aatir | 186ce8c | 2019-10-20 15:13:39 -0500 | [diff] [blame] | 405 | } | 
|  | 406 | } | 
|  | 407 |  | 
| Matt Spinler | acb7c10 | 2020-01-10 13:49:22 -0600 | [diff] [blame] | 408 | std::map<uint16_t, size_t> PEL::getPluralSections() const | 
|  | 409 | { | 
|  | 410 | std::map<uint16_t, size_t> sectionCounts; | 
|  | 411 |  | 
|  | 412 | for (const auto& section : optionalSections()) | 
|  | 413 | { | 
|  | 414 | if (sectionCounts.find(section->header().id) == sectionCounts.end()) | 
|  | 415 | { | 
|  | 416 | sectionCounts[section->header().id] = 1; | 
|  | 417 | } | 
|  | 418 | else | 
|  | 419 | { | 
|  | 420 | sectionCounts[section->header().id]++; | 
|  | 421 | } | 
|  | 422 | } | 
|  | 423 |  | 
|  | 424 | std::map<uint16_t, size_t> sections; | 
|  | 425 | for (const auto& [id, count] : sectionCounts) | 
|  | 426 | { | 
|  | 427 | if (count > 1) | 
|  | 428 | { | 
|  | 429 | // Start with 0 here and printSectionInJSON() | 
|  | 430 | // will increment it as it goes. | 
|  | 431 | sections.emplace(id, 0); | 
|  | 432 | } | 
|  | 433 | } | 
|  | 434 |  | 
|  | 435 | return sections; | 
|  | 436 | } | 
|  | 437 |  | 
| Harisuddin Mohamed Isa | f67bafd | 2020-07-06 17:51:21 +0800 | [diff] [blame] | 438 | void PEL::toJSON(message::Registry& registry, | 
|  | 439 | const std::vector<std::string>& plugins) const | 
| Aatir | 186ce8c | 2019-10-20 15:13:39 -0500 | [diff] [blame] | 440 | { | 
| Matt Spinler | acb7c10 | 2020-01-10 13:49:22 -0600 | [diff] [blame] | 441 | auto sections = getPluralSections(); | 
|  | 442 |  | 
| Harisuddin Mohamed Isa | a214ed3 | 2020-02-28 15:58:23 +0800 | [diff] [blame] | 443 | std::string buf = "{\n"; | 
| Harisuddin Mohamed Isa | f67bafd | 2020-07-06 17:51:21 +0800 | [diff] [blame] | 444 | printSectionInJSON(*(_ph.get()), buf, sections, registry, plugins); | 
|  | 445 | printSectionInJSON(*(_uh.get()), buf, sections, registry, plugins); | 
| Aatir | 186ce8c | 2019-10-20 15:13:39 -0500 | [diff] [blame] | 446 | for (auto& section : this->optionalSections()) | 
|  | 447 | { | 
| Harisuddin Mohamed Isa | f67bafd | 2020-07-06 17:51:21 +0800 | [diff] [blame] | 448 | printSectionInJSON(*(section.get()), buf, sections, registry, plugins, | 
|  | 449 | _ph->creatorID()); | 
| Aatir | 186ce8c | 2019-10-20 15:13:39 -0500 | [diff] [blame] | 450 | } | 
|  | 451 | buf += "}"; | 
|  | 452 | std::size_t found = buf.rfind(","); | 
|  | 453 | if (found != std::string::npos) | 
|  | 454 | buf.replace(found, 1, ""); | 
|  | 455 | std::cout << buf << std::endl; | 
|  | 456 | } | 
| Harisuddin Mohamed Isa | 600d15a | 2019-12-20 12:42:26 +0800 | [diff] [blame] | 457 |  | 
| Matt Spinler | 85f61a6 | 2020-06-03 16:28:55 -0500 | [diff] [blame] | 458 | bool PEL::addUserDataSection(std::unique_ptr<UserData> userData) | 
|  | 459 | { | 
|  | 460 | if (size() + userData->header().size > _maxPELSize) | 
|  | 461 | { | 
|  | 462 | if (userData->shrink(_maxPELSize - size())) | 
|  | 463 | { | 
|  | 464 | _optionalSections.push_back(std::move(userData)); | 
|  | 465 | } | 
|  | 466 | else | 
|  | 467 | { | 
|  | 468 | log<level::WARNING>( | 
|  | 469 | "Could not shrink UserData section. Dropping", | 
|  | 470 | entry("SECTION_SIZE=%d\n", userData->header().size), | 
|  | 471 | entry("COMPONENT_ID=0x%02X", userData->header().componentID), | 
|  | 472 | entry("SUBTYPE=0x%X", userData->header().subType), | 
|  | 473 | entry("VERSION=0x%X", userData->header().version)); | 
|  | 474 | return false; | 
|  | 475 | } | 
|  | 476 | } | 
|  | 477 | else | 
|  | 478 | { | 
|  | 479 | _optionalSections.push_back(std::move(userData)); | 
|  | 480 | } | 
|  | 481 | return true; | 
|  | 482 | } | 
|  | 483 |  | 
| Matt Spinler | 5a90a95 | 2020-08-27 09:39:03 -0500 | [diff] [blame] | 484 | nlohmann::json PEL::getCalloutJSON(const PelFFDC& ffdcFiles) | 
|  | 485 | { | 
|  | 486 | nlohmann::json callouts; | 
|  | 487 |  | 
|  | 488 | for (const auto& file : ffdcFiles) | 
|  | 489 | { | 
|  | 490 | if ((file.format == UserDataFormat::json) && | 
|  | 491 | (file.subType == jsonCalloutSubtype)) | 
|  | 492 | { | 
|  | 493 | auto data = util::readFD(file.fd); | 
|  | 494 | if (data.empty()) | 
|  | 495 | { | 
|  | 496 | throw std::runtime_error{ | 
|  | 497 | "Could not get data from JSON callout file descriptor"}; | 
|  | 498 | } | 
|  | 499 |  | 
|  | 500 | std::string jsonString{data.begin(), data.begin() + data.size()}; | 
|  | 501 |  | 
|  | 502 | callouts = nlohmann::json::parse(jsonString); | 
|  | 503 | break; | 
|  | 504 | } | 
|  | 505 | } | 
|  | 506 |  | 
|  | 507 | return callouts; | 
|  | 508 | } | 
|  | 509 |  | 
| Andrew Geissler | f8e750d | 2022-01-14 14:56:13 -0600 | [diff] [blame] | 510 | bool PEL::isHwCalloutPresent() const | 
| Andrew Geissler | 44fc316 | 2020-07-09 09:21:31 -0500 | [diff] [blame] | 511 | { | 
|  | 512 | auto pSRC = primarySRC(); | 
|  | 513 | if (!pSRC) | 
|  | 514 | { | 
|  | 515 | return false; | 
|  | 516 | } | 
|  | 517 |  | 
|  | 518 | bool calloutPresent = false; | 
|  | 519 | if ((*pSRC)->callouts()) | 
|  | 520 | { | 
|  | 521 | for (auto& i : (*pSRC)->callouts()->callouts()) | 
|  | 522 | { | 
|  | 523 | if (((*i).fruIdentity())) | 
|  | 524 | { | 
|  | 525 | auto& fruId = (*i).fruIdentity(); | 
| Andrew Geissler | f8e750d | 2022-01-14 14:56:13 -0600 | [diff] [blame] | 526 | if ((*fruId).failingComponentType() == | 
|  | 527 | src::FRUIdentity::hardwareFRU) | 
| Andrew Geissler | 44fc316 | 2020-07-09 09:21:31 -0500 | [diff] [blame] | 528 | { | 
|  | 529 | calloutPresent = true; | 
|  | 530 | break; | 
|  | 531 | } | 
|  | 532 | } | 
|  | 533 | } | 
|  | 534 | } | 
|  | 535 |  | 
|  | 536 | return calloutPresent; | 
|  | 537 | } | 
|  | 538 |  | 
| Sumit Kumar | 3160a54 | 2021-04-26 08:07:04 -0500 | [diff] [blame] | 539 | void PEL::updateSysInfoInExtendedUserDataSection( | 
|  | 540 | const DataInterfaceBase& dataIface) | 
|  | 541 | { | 
|  | 542 | const AdditionalData additionalData; | 
|  | 543 |  | 
|  | 544 | // Check for PEL from Hostboot | 
|  | 545 | if (_ph->creatorID() == static_cast<uint8_t>(CreatorID::hostboot)) | 
|  | 546 | { | 
|  | 547 | // Get the ED section from PEL | 
|  | 548 | auto op = std::find_if(_optionalSections.begin(), | 
|  | 549 | _optionalSections.end(), [](auto& section) { | 
|  | 550 | return section->header().id == | 
|  | 551 | static_cast<uint16_t>( | 
|  | 552 | SectionID::extUserData); | 
|  | 553 | }); | 
|  | 554 |  | 
|  | 555 | // Check for ED section found and its not the last section of PEL | 
|  | 556 | if (op != _optionalSections.end()) | 
|  | 557 | { | 
|  | 558 | // Get the extended user data class mapped to found section | 
|  | 559 | auto extUserData = static_cast<ExtendedUserData*>(op->get()); | 
|  | 560 |  | 
|  | 561 | // Check for the creator ID is for OpenBMC | 
|  | 562 | if (extUserData->creatorID() == | 
|  | 563 | static_cast<uint8_t>(CreatorID::openBMC)) | 
|  | 564 | { | 
|  | 565 | // Update subtype and component id | 
|  | 566 | auto subType = static_cast<uint8_t>(UserDataFormat::json); | 
|  | 567 | auto componentId = | 
|  | 568 | static_cast<uint16_t>(ComponentID::phosphorLogging); | 
|  | 569 |  | 
|  | 570 | // Update system data to ED section | 
|  | 571 | auto ud = | 
|  | 572 | util::makeSysInfoUserDataSection(additionalData, dataIface); | 
|  | 573 | extUserData->updateDataSection(subType, componentId, | 
|  | 574 | ud->data()); | 
|  | 575 | } | 
|  | 576 | } | 
|  | 577 | } | 
|  | 578 | } | 
|  | 579 |  | 
| Sumit Kumar | 3e27443 | 2021-09-14 06:37:56 -0500 | [diff] [blame] | 580 | void PEL::updateTerminateBitInSRCSection() | 
|  | 581 | { | 
|  | 582 | //  Check for pel severity of type - 0x51 = critical error, system | 
|  | 583 | //  termination | 
|  | 584 | if (_uh->severity() == 0x51) | 
|  | 585 | { | 
|  | 586 | // Get the primary SRC section | 
|  | 587 | auto pSRC = primarySRC(); | 
|  | 588 | if (pSRC) | 
|  | 589 | { | 
|  | 590 | (*pSRC)->setTerminateBit(); | 
|  | 591 | } | 
|  | 592 | } | 
|  | 593 | } | 
|  | 594 |  | 
| Matt Spinler | c7c3e40 | 2020-01-22 15:07:25 -0600 | [diff] [blame] | 595 | namespace util | 
|  | 596 | { | 
|  | 597 |  | 
| Matt Spinler | 4dcd3f4 | 2020-01-22 14:55:07 -0600 | [diff] [blame] | 598 | std::unique_ptr<UserData> makeJSONUserDataSection(const nlohmann::json& json) | 
|  | 599 | { | 
|  | 600 | auto jsonString = json.dump(); | 
|  | 601 | std::vector<uint8_t> jsonData(jsonString.begin(), jsonString.end()); | 
|  | 602 |  | 
|  | 603 | // Pad to a 4 byte boundary | 
|  | 604 | while ((jsonData.size() % 4) != 0) | 
|  | 605 | { | 
|  | 606 | jsonData.push_back(0); | 
|  | 607 | } | 
|  | 608 |  | 
|  | 609 | return std::make_unique<UserData>( | 
|  | 610 | static_cast<uint16_t>(ComponentID::phosphorLogging), | 
|  | 611 | static_cast<uint8_t>(UserDataFormat::json), | 
|  | 612 | static_cast<uint8_t>(UserDataFormatVersion::json), jsonData); | 
|  | 613 | } | 
|  | 614 |  | 
| Matt Spinler | c7c3e40 | 2020-01-22 15:07:25 -0600 | [diff] [blame] | 615 | std::unique_ptr<UserData> makeADUserDataSection(const AdditionalData& ad) | 
|  | 616 | { | 
|  | 617 | assert(!ad.empty()); | 
|  | 618 | nlohmann::json json; | 
|  | 619 |  | 
|  | 620 | // Remove the 'ESEL' entry, as it contains a full PEL in the value. | 
|  | 621 | if (ad.getValue("ESEL")) | 
|  | 622 | { | 
|  | 623 | auto newAD = ad; | 
|  | 624 | newAD.remove("ESEL"); | 
|  | 625 | json = newAD.toJSON(); | 
|  | 626 | } | 
|  | 627 | else | 
|  | 628 | { | 
|  | 629 | json = ad.toJSON(); | 
|  | 630 | } | 
|  | 631 |  | 
| Matt Spinler | 4dcd3f4 | 2020-01-22 14:55:07 -0600 | [diff] [blame] | 632 | return makeJSONUserDataSection(json); | 
|  | 633 | } | 
| Matt Spinler | c7c3e40 | 2020-01-22 15:07:25 -0600 | [diff] [blame] | 634 |  | 
| Matt Spinler | 4dcd3f4 | 2020-01-22 14:55:07 -0600 | [diff] [blame] | 635 | void addProcessNameToJSON(nlohmann::json& json, | 
|  | 636 | const std::optional<std::string>& pid, | 
|  | 637 | const DataInterfaceBase& dataIface) | 
|  | 638 | { | 
| Matt Spinler | 677381b | 2020-01-23 10:04:29 -0600 | [diff] [blame] | 639 | std::string name{unknownValue}; | 
| Matt Spinler | 4dcd3f4 | 2020-01-22 14:55:07 -0600 | [diff] [blame] | 640 |  | 
|  | 641 | try | 
| Matt Spinler | c7c3e40 | 2020-01-22 15:07:25 -0600 | [diff] [blame] | 642 | { | 
| Matt Spinler | 4dcd3f4 | 2020-01-22 14:55:07 -0600 | [diff] [blame] | 643 | if (pid) | 
|  | 644 | { | 
|  | 645 | auto n = dataIface.getProcessName(*pid); | 
|  | 646 | if (n) | 
|  | 647 | { | 
|  | 648 | name = *n; | 
|  | 649 | } | 
|  | 650 | } | 
|  | 651 | } | 
| Patrick Williams | 66491c6 | 2021-10-06 12:23:37 -0500 | [diff] [blame] | 652 | catch (const std::exception& e) | 
| Matt Spinler | 4dcd3f4 | 2020-01-22 14:55:07 -0600 | [diff] [blame] | 653 | { | 
| Matt Spinler | c7c3e40 | 2020-01-22 15:07:25 -0600 | [diff] [blame] | 654 | } | 
|  | 655 |  | 
| Sumit Kumar | 3160a54 | 2021-04-26 08:07:04 -0500 | [diff] [blame] | 656 | if (pid) | 
|  | 657 | { | 
|  | 658 | json["Process Name"] = std::move(name); | 
|  | 659 | } | 
| Matt Spinler | 4dcd3f4 | 2020-01-22 14:55:07 -0600 | [diff] [blame] | 660 | } | 
|  | 661 |  | 
| Matt Spinler | 677381b | 2020-01-23 10:04:29 -0600 | [diff] [blame] | 662 | void addBMCFWVersionIDToJSON(nlohmann::json& json, | 
|  | 663 | const DataInterfaceBase& dataIface) | 
|  | 664 | { | 
|  | 665 | auto id = dataIface.getBMCFWVersionID(); | 
|  | 666 | if (id.empty()) | 
|  | 667 | { | 
|  | 668 | id = unknownValue; | 
|  | 669 | } | 
|  | 670 |  | 
| Matt Spinler | c2b8a51 | 2021-05-21 12:44:42 -0600 | [diff] [blame] | 671 | json["FW Version ID"] = std::move(id); | 
| Matt Spinler | 677381b | 2020-01-23 10:04:29 -0600 | [diff] [blame] | 672 | } | 
|  | 673 |  | 
| Matt Spinler | 4aa23a1 | 2020-02-03 15:05:09 -0600 | [diff] [blame] | 674 | std::string lastSegment(char separator, std::string data) | 
|  | 675 | { | 
|  | 676 | auto pos = data.find_last_of(separator); | 
|  | 677 | if (pos != std::string::npos) | 
|  | 678 | { | 
|  | 679 | data = data.substr(pos + 1); | 
|  | 680 | } | 
|  | 681 |  | 
|  | 682 | return data; | 
|  | 683 | } | 
|  | 684 |  | 
| Ben Tyner | e32b7e7 | 2021-05-18 12:38:40 -0500 | [diff] [blame] | 685 | void addIMKeyword(nlohmann::json& json, const DataInterfaceBase& dataIface) | 
|  | 686 | { | 
|  | 687 | auto keyword = dataIface.getSystemIMKeyword(); | 
|  | 688 |  | 
|  | 689 | std::string value{}; | 
|  | 690 |  | 
|  | 691 | std::for_each(keyword.begin(), keyword.end(), [&](const auto& byte) { | 
|  | 692 | value += fmt::format("{:02X}", byte); | 
|  | 693 | }); | 
|  | 694 |  | 
|  | 695 | json["System IM"] = value; | 
|  | 696 | } | 
|  | 697 |  | 
| Matt Spinler | 4aa23a1 | 2020-02-03 15:05:09 -0600 | [diff] [blame] | 698 | void addStatesToJSON(nlohmann::json& json, const DataInterfaceBase& dataIface) | 
|  | 699 | { | 
|  | 700 | json["BMCState"] = lastSegment('.', dataIface.getBMCState()); | 
|  | 701 | json["ChassisState"] = lastSegment('.', dataIface.getChassisState()); | 
|  | 702 | json["HostState"] = lastSegment('.', dataIface.getHostState()); | 
| Sumit Kumar | 2c36fdd | 2021-09-21 03:12:11 -0500 | [diff] [blame] | 703 | json["BootState"] = lastSegment('.', dataIface.getBootState()); | 
| Matt Spinler | 4aa23a1 | 2020-02-03 15:05:09 -0600 | [diff] [blame] | 704 | } | 
|  | 705 |  | 
| Matt Spinler | 4dcd3f4 | 2020-01-22 14:55:07 -0600 | [diff] [blame] | 706 | std::unique_ptr<UserData> | 
|  | 707 | makeSysInfoUserDataSection(const AdditionalData& ad, | 
|  | 708 | const DataInterfaceBase& dataIface) | 
|  | 709 | { | 
|  | 710 | nlohmann::json json; | 
|  | 711 |  | 
|  | 712 | addProcessNameToJSON(json, ad.getValue("_PID"), dataIface); | 
| Matt Spinler | 677381b | 2020-01-23 10:04:29 -0600 | [diff] [blame] | 713 | addBMCFWVersionIDToJSON(json, dataIface); | 
| Ben Tyner | e32b7e7 | 2021-05-18 12:38:40 -0500 | [diff] [blame] | 714 | addIMKeyword(json, dataIface); | 
| Matt Spinler | 4aa23a1 | 2020-02-03 15:05:09 -0600 | [diff] [blame] | 715 | addStatesToJSON(json, dataIface); | 
| Matt Spinler | 4dcd3f4 | 2020-01-22 14:55:07 -0600 | [diff] [blame] | 716 |  | 
|  | 717 | return makeJSONUserDataSection(json); | 
| Matt Spinler | c7c3e40 | 2020-01-22 15:07:25 -0600 | [diff] [blame] | 718 | } | 
|  | 719 |  | 
| Matt Spinler | 5b289b2 | 2020-03-26 14:27:19 -0500 | [diff] [blame] | 720 | std::vector<uint8_t> readFD(int fd) | 
|  | 721 | { | 
|  | 722 | std::vector<uint8_t> data; | 
|  | 723 |  | 
|  | 724 | // Get the size | 
|  | 725 | struct stat s; | 
|  | 726 | int r = fstat(fd, &s); | 
|  | 727 | if (r != 0) | 
|  | 728 | { | 
|  | 729 | auto e = errno; | 
|  | 730 | log<level::ERR>("Could not get FFDC file size from FD", | 
|  | 731 | entry("ERRNO=%d", e)); | 
|  | 732 | return data; | 
|  | 733 | } | 
|  | 734 |  | 
|  | 735 | if (0 == s.st_size) | 
|  | 736 | { | 
|  | 737 | log<level::ERR>("FFDC file is empty"); | 
|  | 738 | return data; | 
|  | 739 | } | 
|  | 740 |  | 
|  | 741 | data.resize(s.st_size); | 
|  | 742 |  | 
|  | 743 | // Make sure its at the beginning, as maybe another | 
|  | 744 | // extension already used it. | 
|  | 745 | r = lseek(fd, 0, SEEK_SET); | 
|  | 746 | if (r == -1) | 
|  | 747 | { | 
|  | 748 | auto e = errno; | 
|  | 749 | log<level::ERR>("Could not seek to beginning of FFDC file", | 
|  | 750 | entry("ERRNO=%d", e)); | 
|  | 751 | return data; | 
|  | 752 | } | 
|  | 753 |  | 
|  | 754 | r = read(fd, data.data(), s.st_size); | 
|  | 755 | if (r == -1) | 
|  | 756 | { | 
|  | 757 | auto e = errno; | 
|  | 758 | log<level::ERR>("Could not read FFDC file", entry("ERRNO=%d", e)); | 
|  | 759 | } | 
|  | 760 | else if (r != s.st_size) | 
|  | 761 | { | 
|  | 762 | log<level::WARNING>("Could not read full FFDC file", | 
|  | 763 | entry("FILE_SIZE=%d", s.st_size), | 
|  | 764 | entry("SIZE_READ=%d", r)); | 
|  | 765 | } | 
|  | 766 |  | 
|  | 767 | return data; | 
|  | 768 | } | 
|  | 769 |  | 
| Matt Spinler | 56ad2a0 | 2020-03-26 14:00:52 -0500 | [diff] [blame] | 770 | std::unique_ptr<UserData> makeFFDCuserDataSection(uint16_t componentID, | 
|  | 771 | const PelFFDCfile& file) | 
|  | 772 | { | 
| Matt Spinler | 5b289b2 | 2020-03-26 14:27:19 -0500 | [diff] [blame] | 773 | auto data = readFD(file.fd); | 
|  | 774 |  | 
|  | 775 | if (data.empty()) | 
|  | 776 | { | 
|  | 777 | return std::unique_ptr<UserData>(); | 
|  | 778 | } | 
|  | 779 |  | 
|  | 780 | // The data needs 4 Byte alignment, and save amount padded for the | 
|  | 781 | // CBOR case. | 
|  | 782 | uint32_t pad = 0; | 
|  | 783 | while (data.size() % 4) | 
|  | 784 | { | 
|  | 785 | data.push_back(0); | 
|  | 786 | pad++; | 
|  | 787 | } | 
|  | 788 |  | 
|  | 789 | // For JSON, CBOR, and Text use our component ID, subType, and version, | 
|  | 790 | // otherwise use the supplied ones. | 
|  | 791 | uint16_t compID = static_cast<uint16_t>(ComponentID::phosphorLogging); | 
|  | 792 | uint8_t subType{}; | 
|  | 793 | uint8_t version{}; | 
|  | 794 |  | 
|  | 795 | switch (file.format) | 
|  | 796 | { | 
|  | 797 | case UserDataFormat::json: | 
|  | 798 | subType = static_cast<uint8_t>(UserDataFormat::json); | 
|  | 799 | version = static_cast<uint8_t>(UserDataFormatVersion::json); | 
|  | 800 | break; | 
|  | 801 | case UserDataFormat::cbor: | 
|  | 802 | subType = static_cast<uint8_t>(UserDataFormat::cbor); | 
|  | 803 | version = static_cast<uint8_t>(UserDataFormatVersion::cbor); | 
|  | 804 |  | 
|  | 805 | // The CBOR parser will fail on the extra pad bytes since they | 
|  | 806 | // aren't CBOR.  Add the amount we padded to the end and other | 
|  | 807 | // code will remove it all before parsing. | 
|  | 808 | { | 
|  | 809 | data.resize(data.size() + 4); | 
|  | 810 | Stream stream{data}; | 
|  | 811 | stream.offset(data.size() - 4); | 
|  | 812 | stream << pad; | 
|  | 813 | } | 
|  | 814 |  | 
|  | 815 | break; | 
|  | 816 | case UserDataFormat::text: | 
|  | 817 | subType = static_cast<uint8_t>(UserDataFormat::text); | 
|  | 818 | version = static_cast<uint8_t>(UserDataFormatVersion::text); | 
|  | 819 | break; | 
|  | 820 | case UserDataFormat::custom: | 
|  | 821 | default: | 
|  | 822 | // Use the passed in values | 
|  | 823 | compID = componentID; | 
|  | 824 | subType = file.subType; | 
|  | 825 | version = file.version; | 
|  | 826 | break; | 
|  | 827 | } | 
|  | 828 |  | 
|  | 829 | return std::make_unique<UserData>(compID, subType, version, data); | 
| Matt Spinler | 56ad2a0 | 2020-03-26 14:00:52 -0500 | [diff] [blame] | 830 | } | 
|  | 831 |  | 
| Matt Spinler | c7c3e40 | 2020-01-22 15:07:25 -0600 | [diff] [blame] | 832 | } // namespace util | 
|  | 833 |  | 
| Matt Spinler | cb6b059 | 2019-07-16 15:58:51 -0500 | [diff] [blame] | 834 | } // namespace pels | 
|  | 835 | } // namespace openpower |