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