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