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 */ 16 #include "extended_user_header.hpp" 17 18 #include "json_utils.hpp" 19 #include "pel_types.hpp" 20 #include "pel_values.hpp" 21 22 #include <phosphor-logging/lg2.hpp> 23 24 #include <format> 25 26 namespace openpower 27 { 28 namespace pels 29 { 30 31 namespace pv = openpower::pels::pel_values; 32 33 const size_t defaultSymptomIDWord = 3; 34 const size_t symptomIDMaxSize = 80; 35 36 ExtendedUserHeader::ExtendedUserHeader(Stream& pel) 37 { 38 try 39 { 40 unflatten(pel); 41 validate(); 42 } 43 catch (const std::exception& e) 44 { 45 lg2::error("Cannot unflatten extended user header: {EXCEPTION}", 46 "EXCEPTION", e); 47 _valid = false; 48 } 49 } 50 51 ExtendedUserHeader::ExtendedUserHeader(const DataInterfaceBase& dataIface, 52 const message::Entry& regEntry, 53 const SRC& src) : 54 _mtms(dataIface.getMachineTypeModel(), dataIface.getMachineSerialNumber()) 55 { 56 _header.id = static_cast<uint16_t>(SectionID::extendedUserHeader); 57 _header.version = extendedUserHeaderVersion; 58 _header.subType = 0; 59 _header.componentID = static_cast<uint16_t>(ComponentID::phosphorLogging); 60 61 memset(_serverFWVersion.data(), 0, _serverFWVersion.size()); 62 auto version = dataIface.getServerFWVersion(); 63 64 // The last byte must always be the NULL terminator 65 for (size_t i = 0; i < version.size() && i < firmwareVersionSize - 1; i++) 66 { 67 _serverFWVersion[i] = version[i]; 68 } 69 70 memset(_subsystemFWVersion.data(), 0, _subsystemFWVersion.size()); 71 version = dataIface.getBMCFWVersion(); 72 73 // The last byte must always be the NULL terminator 74 for (size_t i = 0; i < version.size() && i < firmwareVersionSize - 1; i++) 75 { 76 _subsystemFWVersion[i] = version[i]; 77 } 78 79 createSymptomID(regEntry, src); 80 81 _header.size = flattenedSize(); 82 _valid = true; 83 } 84 85 void ExtendedUserHeader::flatten(Stream& pel) const 86 { 87 pel << _header << _mtms; 88 pel.write(_serverFWVersion.data(), _serverFWVersion.size()); 89 pel.write(_subsystemFWVersion.data(), _subsystemFWVersion.size()); 90 pel << _reserved4B << _refTime << _reserved1B1 << _reserved1B2 91 << _reserved1B3 << _symptomIDSize << _symptomID; 92 } 93 94 void ExtendedUserHeader::unflatten(Stream& pel) 95 { 96 pel >> _header >> _mtms; 97 pel.read(_serverFWVersion.data(), _serverFWVersion.size()); 98 pel.read(_subsystemFWVersion.data(), _subsystemFWVersion.size()); 99 pel >> _reserved4B >> _refTime >> _reserved1B1 >> _reserved1B2 >> 100 _reserved1B3 >> _symptomIDSize; 101 102 _symptomID.resize(_symptomIDSize); 103 pel >> _symptomID; 104 } 105 106 void ExtendedUserHeader::validate() 107 { 108 bool failed = false; 109 110 if (header().id != static_cast<uint16_t>(SectionID::extendedUserHeader)) 111 { 112 lg2::error("Invalid ExtendedUserHeader section ID: {HEADER_ID}", 113 "HEADER_ID", lg2::hex, header().id); 114 failed = true; 115 } 116 117 if (header().version != extendedUserHeaderVersion) 118 { 119 lg2::error("Invalid ExtendedUserHeader version: {HEADER_VERSION}", 120 "HEADER_VERSION", lg2::hex, header().version); 121 failed = true; 122 } 123 124 _valid = (failed) ? false : true; 125 } 126 127 void ExtendedUserHeader::createSymptomID(const message::Entry& regEntry, 128 const SRC& src) 129 { 130 // Contains the first 8 characters of the ASCII string plus additional 131 // words from the SRC, separated by underscores. The message registry 132 // says which words to use, though that's optional and if not present 133 // then use a default word. 134 std::vector<size_t> idWords; 135 136 if (regEntry.src.symptomID) 137 { 138 idWords = regEntry.src.symptomID.value(); 139 } 140 else 141 { 142 idWords.push_back(defaultSymptomIDWord); 143 } 144 145 auto symptomID = src.asciiString().substr(0, 8); 146 147 const auto& hexWords = src.hexwordData(); 148 149 for (auto wordNum : idWords) 150 { 151 symptomID.push_back('_'); 152 153 // Get the hexword array index for this SRC word 154 auto index = src.getWordIndexFromWordNum(wordNum); 155 156 // Convert to ASCII 157 char word[20]; 158 sprintf(word, "%08X", hexWords[index]); 159 symptomID += word; 160 } 161 162 std::copy(symptomID.begin(), symptomID.end(), 163 std::back_inserter(_symptomID)); 164 165 // Max total size is 80, including the upcoming NULL 166 if (_symptomID.size() > (symptomIDMaxSize - 1)) 167 { 168 _symptomID.resize(symptomIDMaxSize - 1); 169 } 170 171 // NULL terminated 172 _symptomID.push_back(0); 173 174 // PAD with NULLs to a 4 byte boundary 175 while ((_symptomID.size() % 4) != 0) 176 { 177 _symptomID.push_back(0); 178 } 179 180 _symptomIDSize = _symptomID.size(); 181 } 182 183 std::optional<std::string> ExtendedUserHeader::getJSON(uint8_t creatorID) const 184 { 185 std::string json; 186 jsonInsert(json, pv::sectionVer, getNumberString("%d", _header.version), 1); 187 jsonInsert(json, pv::subSection, getNumberString("%d", _header.subType), 1); 188 jsonInsert(json, pv::createdBy, 189 getComponentName(_header.componentID, creatorID), 1); 190 jsonInsert(json, "Reporting Machine Type", machineTypeModel(), 1); 191 jsonInsert(json, "Reporting Serial Number", trimEnd(machineSerialNumber()), 192 1); 193 jsonInsert(json, "FW Released Ver", serverFWVersion(), 1); 194 jsonInsert(json, "FW SubSys Version", subsystemFWVersion(), 1); 195 jsonInsert(json, "Common Ref Time", 196 getNumberString("%02X", _refTime.month) + '/' + 197 getNumberString("%02X", _refTime.day) + '/' + 198 getNumberString("%02X", _refTime.yearMSB) + 199 getNumberString("%02X", _refTime.yearLSB) + ' ' + 200 getNumberString("%02X", _refTime.hour) + ':' + 201 getNumberString("%02X", _refTime.minutes) + ':' + 202 getNumberString("%02X", _refTime.seconds), 203 1); 204 jsonInsert(json, "Symptom Id Len", getNumberString("%d", _symptomIDSize), 205 1); 206 jsonInsert(json, "Symptom Id", symptomID(), 1); 207 json.erase(json.size() - 2); 208 return json; 209 } 210 211 } // namespace pels 212 } // namespace openpower 213