diff options
Diffstat (limited to 'extensions/openpower-pels/extended_user_header.cpp')
-rw-r--r-- | extensions/openpower-pels/extended_user_header.cpp | 179 |
1 files changed, 179 insertions, 0 deletions
diff --git a/extensions/openpower-pels/extended_user_header.cpp b/extensions/openpower-pels/extended_user_header.cpp new file mode 100644 index 0000000..c5c1938 --- /dev/null +++ b/extensions/openpower-pels/extended_user_header.cpp @@ -0,0 +1,179 @@ +/** + * Copyright © 2019 IBM Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "extended_user_header.hpp" + +#include "pel_types.hpp" + +#include <phosphor-logging/log.hpp> + +namespace openpower +{ +namespace pels +{ + +using namespace phosphor::logging; +const size_t defaultSymptomIDWord = 3; +const size_t symptomIDMaxSize = 80; + +ExtendedUserHeader::ExtendedUserHeader(Stream& pel) +{ + try + { + unflatten(pel); + validate(); + } + catch (const std::exception& e) + { + log<level::ERR>("Cannot unflatten extended user header", + entry("ERROR=%s", e.what())); + _valid = false; + } +} + +ExtendedUserHeader::ExtendedUserHeader(const DataInterfaceBase& dataIface, + const message::Entry& regEntry, + const SRC& src) : + _mtms(dataIface.getMachineTypeModel(), dataIface.getMachineSerialNumber()) +{ + _header.id = static_cast<uint16_t>(SectionID::extendedUserHeader); + _header.version = extendedUserHeaderVersion; + _header.subType = 0; + _header.componentID = static_cast<uint16_t>(ComponentID::phosphorLogging); + + memset(_serverFWVersion.data(), 0, _serverFWVersion.size()); + auto version = dataIface.getServerFWVersion(); + + // The last byte must always be the NULL terminator + for (size_t i = 0; i < version.size() && i < firmwareVersionSize - 1; i++) + { + _serverFWVersion[i] = version[i]; + } + + memset(_subsystemFWVersion.data(), 0, _subsystemFWVersion.size()); + version = dataIface.getBMCFWVersion(); + + // The last byte must always be the NULL terminator + for (size_t i = 0; i < version.size() && i < firmwareVersionSize - 1; i++) + { + _subsystemFWVersion[i] = version[i]; + } + + createSymptomID(regEntry, src); + + _header.size = flattenedSize(); + _valid = true; +} + +void ExtendedUserHeader::flatten(Stream& pel) const +{ + pel << _header << _mtms; + pel.write(_serverFWVersion.data(), _serverFWVersion.size()); + pel.write(_subsystemFWVersion.data(), _subsystemFWVersion.size()); + pel << _reserved4B << _refTime << _reserved1B1 << _reserved1B2 + << _reserved1B3 << _symptomIDSize << _symptomID; +} + +void ExtendedUserHeader::unflatten(Stream& pel) +{ + pel >> _header >> _mtms; + pel.read(_serverFWVersion.data(), _serverFWVersion.size()); + pel.read(_subsystemFWVersion.data(), _subsystemFWVersion.size()); + pel >> _reserved4B >> _refTime >> _reserved1B1 >> _reserved1B2 >> + _reserved1B3 >> _symptomIDSize; + + _symptomID.resize(_symptomIDSize); + pel >> _symptomID; +} + +void ExtendedUserHeader::validate() +{ + bool failed = false; + + if (header().id != static_cast<uint16_t>(SectionID::extendedUserHeader)) + { + log<level::ERR>("Invalid failing Extended User Header section ID", + entry("ID=0x%X", header().id)); + failed = true; + } + + if (header().version != extendedUserHeaderVersion) + { + log<level::ERR>("Invalid Extended User Header version", + entry("VERSION=0x%X", header().version)); + failed = true; + } + + _valid = (failed) ? false : true; +} + +void ExtendedUserHeader::createSymptomID(const message::Entry& regEntry, + const SRC& src) +{ + // Contains the first 8 characters of the ASCII string plus additional + // words from the SRC, separated by underscores. The message registry + // says which words to use, though that's optional and if not present + // then use a default word. + std::vector<size_t> idWords; + + if (regEntry.src.symptomID) + { + idWords = regEntry.src.symptomID.value(); + } + else + { + idWords.push_back(defaultSymptomIDWord); + } + + auto symptomID = src.asciiString().substr(0, 8); + + const auto& hexWords = src.hexwordData(); + + for (auto wordNum : idWords) + { + symptomID.push_back('_'); + + // Get the hexword array index for this SRC word + auto index = src.getWordIndexFromWordNum(wordNum); + + // Convert to ASCII + char word[20]; + sprintf(word, "%08X", hexWords[index]); + symptomID += word; + } + + std::copy(symptomID.begin(), symptomID.end(), + std::back_inserter(_symptomID)); + + // Max total size is 80, including the upcoming NULL + if (_symptomID.size() > (symptomIDMaxSize - 1)) + { + _symptomID.resize(symptomIDMaxSize - 1); + } + + // NULL terminated + _symptomID.push_back(0); + + // PAD with NULLs to a 4 byte boundary + while ((_symptomID.size() % 4) != 0) + { + _symptomID.push_back(0); + } + + _symptomIDSize = _symptomID.size(); +} + +} // namespace pels +} // namespace openpower |