blob: f67ff446e347be203ffd0064fd0ddb6683ae303d [file] [log] [blame]
/**
* 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 "src.hpp"
#include <phosphor-logging/log.hpp>
namespace openpower
{
namespace pels
{
using namespace phosphor::logging;
void SRC::unflatten(Stream& stream)
{
stream >> _header >> _version >> _flags >> _reserved1B >> _wordCount >>
_reserved2B >> _size;
for (auto& word : _hexData)
{
stream >> word;
}
_asciiString = std::make_unique<src::AsciiString>(stream);
if (hasAdditionalSections())
{
// The callouts section is currently the only extra subsection type
_callouts = std::make_unique<src::Callouts>(stream);
}
}
void SRC::flatten(Stream& stream)
{
stream << _header << _version << _flags << _reserved1B << _wordCount
<< _reserved2B << _size;
for (auto& word : _hexData)
{
stream << word;
}
_asciiString->flatten(stream);
if (_callouts)
{
_callouts->flatten(stream);
}
}
SRC::SRC(Stream& pel)
{
try
{
unflatten(pel);
validate();
}
catch (const std::exception& e)
{
log<level::ERR>("Cannot unflatten SRC", entry("ERROR=%s", e.what()));
_valid = false;
}
}
SRC::SRC(const message::Entry& regEntry, const AdditionalData& additionalData)
{
_header.id = static_cast<uint16_t>(SectionID::primarySRC);
_header.version = srcSectionVersion;
_header.subType = srcSectionSubtype;
_header.componentID = regEntry.componentID;
_version = srcVersion;
_flags = 0;
if (regEntry.src.powerFault.value_or(false))
{
_flags |= powerFaultEvent;
}
_reserved1B = 0;
_wordCount = numSRCHexDataWords + 1;
_reserved2B = 0;
// There are multiple fields encoded in the hex data words.
std::for_each(_hexData.begin(), _hexData.end(),
[](auto& word) { word = 0; });
setBMCFormat();
setBMCPosition();
// Partition dump status and partition boot type always 0 for BMC errors.
//
// TODO: Fill in other fields that aren't available yet.
// Fill in the last 4 words from the AdditionalData property contents.
setUserDefinedHexWords(regEntry, additionalData);
_asciiString = std::make_unique<src::AsciiString>(regEntry);
// TODO: add callouts using the Callouts object
_size = baseSRCSize;
_size += _callouts ? _callouts->flattenedSize() : 0;
_header.size = Section::flattenedSize() + _size;
_valid = true;
}
void SRC::setUserDefinedHexWords(const message::Entry& regEntry,
const AdditionalData& ad)
{
if (!regEntry.src.hexwordADFields)
{
return;
}
// Save the AdditionalData value corresponding to the
// adName key in _hexData[wordNum].
for (const auto& [wordNum, adName] : *regEntry.src.hexwordADFields)
{
// Can only set words 6 - 9
if (!isUserDefinedWord(wordNum))
{
log<level::WARNING>("SRC user data word out of range",
entry("WORD_NUM=%d", wordNum),
entry("ERROR_NAME=%s", regEntry.name.c_str()));
continue;
}
auto value = ad.getValue(adName);
if (value)
{
_hexData[getWordIndexFromWordNum(wordNum)] =
std::strtoul(value.value().c_str(), nullptr, 0);
}
else
{
log<level::WARNING>("Source for user data SRC word not found",
entry("ADDITIONALDATA_KEY=%s", adName.c_str()),
entry("ERROR_NAME=%s", regEntry.name.c_str()));
}
}
}
void SRC::validate()
{
bool failed = false;
if ((header().id != static_cast<uint16_t>(SectionID::primarySRC)) &&
(header().id != static_cast<uint16_t>(SectionID::secondarySRC)))
{
log<level::ERR>("Invalid SRC section ID",
entry("ID=0x%X", header().id));
failed = true;
}
// Check the version in the SRC, not in the header
if (_version != srcVersion)
{
log<level::ERR>("Invalid SRC version", entry("VERSION=0x%X", _version));
failed = true;
}
_valid = failed ? false : true;
}
} // namespace pels
} // namespace openpower