| 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 | */ | 
| Matt Spinler | cb6b059 | 2019-07-16 15:58:51 -0500 | [diff] [blame] | 16 | #include "pel.hpp" | 
|  | 17 |  | 
|  | 18 | #include "bcd_time.hpp" | 
| Matt Spinler | aa65947 | 2019-10-23 09:26:48 -0500 | [diff] [blame] | 19 | #include "failing_mtms.hpp" | 
| Aatir | 186ce8c | 2019-10-20 15:13:39 -0500 | [diff] [blame] | 20 | #include "hexdump.hpp" | 
| Matt Spinler | cb6b059 | 2019-07-16 15:58:51 -0500 | [diff] [blame] | 21 | #include "log_id.hpp" | 
| Matt Spinler | f1e85e2 | 2019-11-01 11:31:31 -0500 | [diff] [blame] | 22 | #include "pel_rules.hpp" | 
| Aatir | 186ce8c | 2019-10-20 15:13:39 -0500 | [diff] [blame] | 23 | #include "pel_values.hpp" | 
| Matt Spinler | 131870c | 2019-09-25 13:29:04 -0500 | [diff] [blame] | 24 | #include "section_factory.hpp" | 
| Matt Spinler | bd716f0 | 2019-10-15 10:54:11 -0500 | [diff] [blame] | 25 | #include "src.hpp" | 
| Matt Spinler | cb6b059 | 2019-07-16 15:58:51 -0500 | [diff] [blame] | 26 | #include "stream.hpp" | 
| Matt Spinler | afa857c | 2019-10-24 13:03:46 -0500 | [diff] [blame] | 27 | #include "user_data_formats.hpp" | 
| Matt Spinler | cb6b059 | 2019-07-16 15:58:51 -0500 | [diff] [blame] | 28 |  | 
| Aatir | 186ce8c | 2019-10-20 15:13:39 -0500 | [diff] [blame] | 29 | #include <iostream> | 
| Matt Spinler | 07eefc5 | 2019-09-26 11:18:26 -0500 | [diff] [blame] | 30 | #include <phosphor-logging/log.hpp> | 
|  | 31 |  | 
| Matt Spinler | cb6b059 | 2019-07-16 15:58:51 -0500 | [diff] [blame] | 32 | namespace openpower | 
|  | 33 | { | 
|  | 34 | namespace pels | 
|  | 35 | { | 
| Matt Spinler | b832363 | 2019-09-20 15:11:04 -0500 | [diff] [blame] | 36 | namespace message = openpower::pels::message; | 
| Aatir | 186ce8c | 2019-10-20 15:13:39 -0500 | [diff] [blame] | 37 | namespace pv = openpower::pels::pel_values; | 
| Matt Spinler | b832363 | 2019-09-20 15:11:04 -0500 | [diff] [blame] | 38 |  | 
|  | 39 | PEL::PEL(const message::Entry& entry, uint32_t obmcLogID, uint64_t timestamp, | 
| Matt Spinler | bd716f0 | 2019-10-15 10:54:11 -0500 | [diff] [blame] | 40 | phosphor::logging::Entry::Level severity, | 
| Matt Spinler | aa65947 | 2019-10-23 09:26:48 -0500 | [diff] [blame] | 41 | const AdditionalData& additionalData, | 
|  | 42 | const DataInterfaceBase& dataIface) | 
| Matt Spinler | b832363 | 2019-09-20 15:11:04 -0500 | [diff] [blame] | 43 | { | 
|  | 44 | _ph = std::make_unique<PrivateHeader>(entry.componentID, obmcLogID, | 
|  | 45 | timestamp); | 
|  | 46 | _uh = std::make_unique<UserHeader>(entry, severity); | 
|  | 47 |  | 
| Matt Spinler | bd716f0 | 2019-10-15 10:54:11 -0500 | [diff] [blame] | 48 | auto src = std::make_unique<SRC>(entry, additionalData); | 
|  | 49 | _optionalSections.push_back(std::move(src)); | 
| Matt Spinler | b832363 | 2019-09-20 15:11:04 -0500 | [diff] [blame] | 50 |  | 
| Matt Spinler | aa65947 | 2019-10-23 09:26:48 -0500 | [diff] [blame] | 51 | auto mtms = std::make_unique<FailingMTMS>(dataIface); | 
|  | 52 | _optionalSections.push_back(std::move(mtms)); | 
| Matt Spinler | bd716f0 | 2019-10-15 10:54:11 -0500 | [diff] [blame] | 53 |  | 
| Matt Spinler | afa857c | 2019-10-24 13:03:46 -0500 | [diff] [blame] | 54 | if (!additionalData.empty()) | 
|  | 55 | { | 
|  | 56 | auto ud = util::makeADUserDataSection(additionalData); | 
|  | 57 | _optionalSections.push_back(std::move(ud)); | 
|  | 58 | } | 
|  | 59 |  | 
| Matt Spinler | 97d19b4 | 2019-10-29 11:34:03 -0500 | [diff] [blame] | 60 | _ph->setSectionCount(2 + _optionalSections.size()); | 
| Matt Spinler | f1e85e2 | 2019-11-01 11:31:31 -0500 | [diff] [blame] | 61 |  | 
|  | 62 | checkRulesAndFix(); | 
| Matt Spinler | b832363 | 2019-09-20 15:11:04 -0500 | [diff] [blame] | 63 | } | 
| Matt Spinler | cb6b059 | 2019-07-16 15:58:51 -0500 | [diff] [blame] | 64 |  | 
| Matt Spinler | 07eefc5 | 2019-09-26 11:18:26 -0500 | [diff] [blame] | 65 | PEL::PEL(std::vector<uint8_t>& data) : PEL(data, 0) | 
| Matt Spinler | cb6b059 | 2019-07-16 15:58:51 -0500 | [diff] [blame] | 66 | { | 
|  | 67 | } | 
|  | 68 |  | 
| Matt Spinler | 07eefc5 | 2019-09-26 11:18:26 -0500 | [diff] [blame] | 69 | PEL::PEL(std::vector<uint8_t>& data, uint32_t obmcLogID) | 
| Matt Spinler | cb6b059 | 2019-07-16 15:58:51 -0500 | [diff] [blame] | 70 | { | 
| Matt Spinler | 07eefc5 | 2019-09-26 11:18:26 -0500 | [diff] [blame] | 71 | populateFromRawData(data, obmcLogID); | 
| Matt Spinler | cb6b059 | 2019-07-16 15:58:51 -0500 | [diff] [blame] | 72 | } | 
|  | 73 |  | 
| Matt Spinler | 07eefc5 | 2019-09-26 11:18:26 -0500 | [diff] [blame] | 74 | void PEL::populateFromRawData(std::vector<uint8_t>& data, uint32_t obmcLogID) | 
| Matt Spinler | cb6b059 | 2019-07-16 15:58:51 -0500 | [diff] [blame] | 75 | { | 
| Matt Spinler | 07eefc5 | 2019-09-26 11:18:26 -0500 | [diff] [blame] | 76 | Stream pelData{data}; | 
| Matt Spinler | cb6b059 | 2019-07-16 15:58:51 -0500 | [diff] [blame] | 77 | _ph = std::make_unique<PrivateHeader>(pelData); | 
|  | 78 | if (obmcLogID != 0) | 
|  | 79 | { | 
| Matt Spinler | 97d19b4 | 2019-10-29 11:34:03 -0500 | [diff] [blame] | 80 | _ph->setOBMCLogID(obmcLogID); | 
| Matt Spinler | cb6b059 | 2019-07-16 15:58:51 -0500 | [diff] [blame] | 81 | } | 
|  | 82 |  | 
|  | 83 | _uh = std::make_unique<UserHeader>(pelData); | 
| Matt Spinler | 131870c | 2019-09-25 13:29:04 -0500 | [diff] [blame] | 84 |  | 
|  | 85 | // Use the section factory to create the rest of the objects | 
|  | 86 | for (size_t i = 2; i < _ph->sectionCount(); i++) | 
|  | 87 | { | 
|  | 88 | auto section = section_factory::create(pelData); | 
|  | 89 | _optionalSections.push_back(std::move(section)); | 
|  | 90 | } | 
| Matt Spinler | cb6b059 | 2019-07-16 15:58:51 -0500 | [diff] [blame] | 91 | } | 
|  | 92 |  | 
|  | 93 | bool PEL::valid() const | 
|  | 94 | { | 
|  | 95 | bool valid = _ph->valid(); | 
|  | 96 |  | 
|  | 97 | if (valid) | 
|  | 98 | { | 
|  | 99 | valid = _uh->valid(); | 
|  | 100 | } | 
|  | 101 |  | 
| Matt Spinler | 131870c | 2019-09-25 13:29:04 -0500 | [diff] [blame] | 102 | if (valid) | 
|  | 103 | { | 
|  | 104 | if (!std::all_of(_optionalSections.begin(), _optionalSections.end(), | 
|  | 105 | [](const auto& section) { return section->valid(); })) | 
|  | 106 | { | 
|  | 107 | valid = false; | 
|  | 108 | } | 
|  | 109 | } | 
|  | 110 |  | 
| Matt Spinler | cb6b059 | 2019-07-16 15:58:51 -0500 | [diff] [blame] | 111 | return valid; | 
|  | 112 | } | 
|  | 113 |  | 
|  | 114 | void PEL::setCommitTime() | 
|  | 115 | { | 
|  | 116 | auto now = std::chrono::system_clock::now(); | 
| Matt Spinler | 97d19b4 | 2019-10-29 11:34:03 -0500 | [diff] [blame] | 117 | _ph->setCommitTimestamp(getBCDTime(now)); | 
| Matt Spinler | cb6b059 | 2019-07-16 15:58:51 -0500 | [diff] [blame] | 118 | } | 
|  | 119 |  | 
|  | 120 | void PEL::assignID() | 
|  | 121 | { | 
| Matt Spinler | 97d19b4 | 2019-10-29 11:34:03 -0500 | [diff] [blame] | 122 | _ph->setID(generatePELID()); | 
| Matt Spinler | cb6b059 | 2019-07-16 15:58:51 -0500 | [diff] [blame] | 123 | } | 
|  | 124 |  | 
| Matt Spinler | 0688545 | 2019-11-06 10:35:42 -0600 | [diff] [blame] | 125 | void PEL::flatten(std::vector<uint8_t>& pelBuffer) const | 
| Matt Spinler | cb6b059 | 2019-07-16 15:58:51 -0500 | [diff] [blame] | 126 | { | 
|  | 127 | Stream pelData{pelBuffer}; | 
| Matt Spinler | b832363 | 2019-09-20 15:11:04 -0500 | [diff] [blame] | 128 |  | 
| Matt Spinler | 07eefc5 | 2019-09-26 11:18:26 -0500 | [diff] [blame] | 129 | if (!valid()) | 
| Matt Spinler | cb6b059 | 2019-07-16 15:58:51 -0500 | [diff] [blame] | 130 | { | 
| Matt Spinler | 07eefc5 | 2019-09-26 11:18:26 -0500 | [diff] [blame] | 131 | using namespace phosphor::logging; | 
|  | 132 | log<level::WARNING>("Unflattening an invalid PEL"); | 
| Matt Spinler | cb6b059 | 2019-07-16 15:58:51 -0500 | [diff] [blame] | 133 | } | 
|  | 134 |  | 
| Matt Spinler | 07eefc5 | 2019-09-26 11:18:26 -0500 | [diff] [blame] | 135 | _ph->flatten(pelData); | 
| Matt Spinler | b832363 | 2019-09-20 15:11:04 -0500 | [diff] [blame] | 136 | _uh->flatten(pelData); | 
| Matt Spinler | 07eefc5 | 2019-09-26 11:18:26 -0500 | [diff] [blame] | 137 |  | 
|  | 138 | for (auto& section : _optionalSections) | 
|  | 139 | { | 
|  | 140 | section->flatten(pelData); | 
|  | 141 | } | 
| Matt Spinler | cb6b059 | 2019-07-16 15:58:51 -0500 | [diff] [blame] | 142 | } | 
|  | 143 |  | 
| Matt Spinler | 0688545 | 2019-11-06 10:35:42 -0600 | [diff] [blame] | 144 | std::vector<uint8_t> PEL::data() const | 
| Matt Spinler | cb6b059 | 2019-07-16 15:58:51 -0500 | [diff] [blame] | 145 | { | 
| Matt Spinler | 07eefc5 | 2019-09-26 11:18:26 -0500 | [diff] [blame] | 146 | std::vector<uint8_t> pelData; | 
|  | 147 | flatten(pelData); | 
|  | 148 | return pelData; | 
| Matt Spinler | cb6b059 | 2019-07-16 15:58:51 -0500 | [diff] [blame] | 149 | } | 
|  | 150 |  | 
| Matt Spinler | bd716f0 | 2019-10-15 10:54:11 -0500 | [diff] [blame] | 151 | std::optional<SRC*> PEL::primarySRC() const | 
|  | 152 | { | 
|  | 153 | auto src = std::find_if( | 
|  | 154 | _optionalSections.begin(), _optionalSections.end(), [](auto& section) { | 
|  | 155 | return section->header().id == | 
|  | 156 | static_cast<uint16_t>(SectionID::primarySRC); | 
|  | 157 | }); | 
|  | 158 | if (src != _optionalSections.end()) | 
|  | 159 | { | 
|  | 160 | return static_cast<SRC*>(src->get()); | 
|  | 161 | } | 
|  | 162 |  | 
|  | 163 | return std::nullopt; | 
|  | 164 | } | 
|  | 165 |  | 
| Matt Spinler | f1e85e2 | 2019-11-01 11:31:31 -0500 | [diff] [blame] | 166 | void PEL::checkRulesAndFix() | 
|  | 167 | { | 
|  | 168 | auto [actionFlags, eventType] = | 
|  | 169 | pel_rules::check(_uh->actionFlags(), _uh->eventType(), _uh->severity()); | 
|  | 170 |  | 
|  | 171 | _uh->setActionFlags(actionFlags); | 
|  | 172 | _uh->setEventType(eventType); | 
|  | 173 | } | 
|  | 174 |  | 
| Matt Spinler | afa857c | 2019-10-24 13:03:46 -0500 | [diff] [blame] | 175 | namespace util | 
|  | 176 | { | 
|  | 177 |  | 
|  | 178 | std::unique_ptr<UserData> makeADUserDataSection(const AdditionalData& ad) | 
|  | 179 | { | 
|  | 180 | assert(!ad.empty()); | 
|  | 181 | nlohmann::json json; | 
|  | 182 |  | 
|  | 183 | // Remove the 'ESEL' entry, as it contains a full PEL in the value. | 
|  | 184 | if (ad.getValue("ESEL")) | 
|  | 185 | { | 
|  | 186 | auto newAD = ad; | 
|  | 187 | newAD.remove("ESEL"); | 
|  | 188 | json = newAD.toJSON(); | 
|  | 189 | } | 
|  | 190 | else | 
|  | 191 | { | 
|  | 192 | json = ad.toJSON(); | 
|  | 193 | } | 
|  | 194 |  | 
|  | 195 | auto jsonString = json.dump(); | 
|  | 196 | std::vector<uint8_t> jsonData(jsonString.begin(), jsonString.end()); | 
|  | 197 |  | 
|  | 198 | return std::make_unique<UserData>( | 
|  | 199 | static_cast<uint16_t>(ComponentID::phosphorLogging), | 
|  | 200 | static_cast<uint8_t>(UserDataFormat::json), | 
|  | 201 | static_cast<uint8_t>(UserDataFormatVersion::json), jsonData); | 
|  | 202 | } | 
|  | 203 |  | 
|  | 204 | } // namespace util | 
| Matt Spinler | 0688545 | 2019-11-06 10:35:42 -0600 | [diff] [blame] | 205 |  | 
|  | 206 | void PEL::printSectionInJSON(const Section& section, std::string& buf) const | 
| Aatir | 186ce8c | 2019-10-20 15:13:39 -0500 | [diff] [blame] | 207 | { | 
|  | 208 | char tmpB[5]; | 
|  | 209 | if (section.valid()) | 
|  | 210 | { | 
|  | 211 | uint8_t id[] = {static_cast<uint8_t>(section.header().id >> 8), | 
|  | 212 | static_cast<uint8_t>(section.header().id)}; | 
|  | 213 | sprintf(tmpB, "%c%c", id[0], id[1]); | 
|  | 214 | std::string sectionID(tmpB); | 
|  | 215 | std::string sectionName = pv::sectionTitles.count(sectionID) | 
|  | 216 | ? pv::sectionTitles.at(sectionID) | 
|  | 217 | : "Unknown Section"; | 
|  | 218 | buf += "\n\"" + sectionName + "\":[\n "; | 
|  | 219 | std::vector<uint8_t> data; | 
|  | 220 | Stream s{data}; | 
|  | 221 | section.flatten(s); | 
|  | 222 | std::string dstr = dumpHex(std::data(data), data.size()); | 
|  | 223 | buf += dstr + "\n],\n"; | 
|  | 224 | } | 
|  | 225 | else | 
|  | 226 | { | 
|  | 227 | buf += "\n\"Invalid Section  \":[\n invalid \n],\n"; | 
|  | 228 | } | 
|  | 229 | } | 
|  | 230 |  | 
| Matt Spinler | 0688545 | 2019-11-06 10:35:42 -0600 | [diff] [blame] | 231 | void PEL::toJSON() const | 
| Aatir | 186ce8c | 2019-10-20 15:13:39 -0500 | [diff] [blame] | 232 | { | 
|  | 233 | std::string buf = "{"; | 
|  | 234 | printSectionInJSON(*(_ph.get()), buf); | 
|  | 235 | printSectionInJSON(*(_uh.get()), buf); | 
|  | 236 | for (auto& section : this->optionalSections()) | 
|  | 237 | { | 
|  | 238 | printSectionInJSON(*(section.get()), buf); | 
|  | 239 | } | 
|  | 240 | buf += "}"; | 
|  | 241 | std::size_t found = buf.rfind(","); | 
|  | 242 | if (found != std::string::npos) | 
|  | 243 | buf.replace(found, 1, ""); | 
|  | 244 | std::cout << buf << std::endl; | 
|  | 245 | } | 
| Matt Spinler | cb6b059 | 2019-07-16 15:58:51 -0500 | [diff] [blame] | 246 | } // namespace pels | 
|  | 247 | } // namespace openpower |