blob: 6ace46b0e7698ccb4d26da7972696723c1c50f1e [file] [log] [blame]
#include "platform.hpp"
#include "utils.hpp"
namespace pldm
{
namespace responder
{
namespace platform
{
using InternalFailure =
sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure;
void Handler::generateStateEffecterRepo(const Json& json, Repo& repo)
{
static const std::vector<Json> emptyList{};
static const Json empty{};
auto entries = json.value("entries", emptyList);
for (const auto& e : entries)
{
size_t pdrSize = 0;
auto effecters = e.value("effecters", emptyList);
static const Json empty{};
for (const auto& effecter : effecters)
{
auto set = effecter.value("set", empty);
auto statesSize = set.value("size", 0);
if (!statesSize)
{
std::cerr << "Malformed PDR JSON return "
"pdrEntry;- no state set "
"info, TYPE="
<< PLDM_STATE_EFFECTER_PDR << "\n";
throw InternalFailure();
}
pdrSize += sizeof(state_effecter_possible_states) -
sizeof(bitfield8_t) + (sizeof(bitfield8_t) * statesSize);
}
pdrSize += sizeof(pldm_state_effecter_pdr) - sizeof(uint8_t);
std::vector<uint8_t> entry{};
entry.resize(pdrSize);
pldm_state_effecter_pdr* pdr =
reinterpret_cast<pldm_state_effecter_pdr*>(entry.data());
pdr->hdr.record_handle = 0;
pdr->hdr.version = 1;
pdr->hdr.type = PLDM_STATE_EFFECTER_PDR;
pdr->hdr.record_change_num = 0;
pdr->hdr.length = pdrSize - sizeof(pldm_pdr_hdr);
pdr->terminus_handle = 0;
pdr->effecter_id = this->getNextEffecterId();
pdr->entity_type = e.value("type", 0);
pdr->entity_instance = e.value("instance", 0);
pdr->container_id = e.value("container", 0);
pdr->effecter_semantic_id = 0;
pdr->effecter_init = PLDM_NO_INIT;
pdr->has_description_pdr = false;
pdr->composite_effecter_count = effecters.size();
EffecterObjs paths{};
uint8_t* start =
entry.data() + sizeof(pldm_state_effecter_pdr) - sizeof(uint8_t);
for (const auto& effecter : effecters)
{
auto set = effecter.value("set", empty);
state_effecter_possible_states* possibleStates =
reinterpret_cast<state_effecter_possible_states*>(start);
possibleStates->state_set_id = set.value("id", 0);
possibleStates->possible_states_size = set.value("size", 0);
start += sizeof(possibleStates->state_set_id) +
sizeof(possibleStates->possible_states_size);
static const std::vector<uint8_t> emptyStates{};
auto states = set.value("states", emptyStates);
for (const auto& state : states)
{
auto index = state / 8;
auto bit = state - (index * 8);
bitfield8_t* bf = reinterpret_cast<bitfield8_t*>(start + index);
bf->byte |= 1 << bit;
}
start += possibleStates->possible_states_size;
auto dbus = effecter.value("dbus", empty);
paths.emplace_back(std::move(dbus));
}
addEffecterObjs(pdr->effecter_id, std::move(paths));
PdrEntry pdrEntry{};
pdrEntry.data = entry.data();
pdrEntry.size = pdrSize;
repo.addRecord(pdrEntry);
}
}
void Handler::generate(const std::string& dir, Repo& repo)
{
// A map of PDR type to a lambda that handles creation of that PDR type.
// The lambda essentially would parse the platform specific PDR JSONs to
// generate the PDR structures. This function iterates through the map to
// invoke all lambdas, so that all PDR types can be created.
const std::map<Type, std::function<void(const Json& json, Repo& repo)>>
generators = {
{PLDM_STATE_EFFECTER_PDR, [this](const auto& json, Repo& repo) {
generateStateEffecterRepo(json, repo);
}}};
Type pdrType{};
for (const auto& dirEntry : fs::directory_iterator(dir))
{
try
{
auto json = readJson(dirEntry.path().string());
if (!json.empty())
{
pdrType = json.value("pdrType", 0);
generators.at(pdrType)(json, repo);
}
}
catch (const InternalFailure& e)
{
std::cerr << "PDR config directory does not exist or empty, TYPE= "
<< pdrType << "PATH= " << dirEntry
<< " ERROR=" << e.what() << "\n";
}
catch (const Json::exception& e)
{
std::cerr << "Failed parsing PDR JSON file, TYPE= " << pdrType
<< " ERROR=" << e.what() << "\n";
pldm::utils::reportError(
"xyz.openbmc_project.bmc.pldm.InternalFailure");
}
catch (const std::exception& e)
{
std::cerr << "Failed parsing PDR JSON file, TYPE= " << pdrType
<< " ERROR=" << e.what() << "\n";
pldm::utils::reportError(
"xyz.openbmc_project.bmc.pldm.InternalFailure");
}
}
}
Response Handler::getPDR(const pldm_msg* request, size_t payloadLength)
{
Response response(sizeof(pldm_msg_hdr) + PLDM_GET_PDR_MIN_RESP_BYTES, 0);
auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
if (payloadLength != PLDM_GET_PDR_REQ_BYTES)
{
return CmdHandler::ccOnlyResponse(request, PLDM_ERROR_INVALID_LENGTH);
}
uint32_t recordHandle{};
uint32_t dataTransferHandle{};
uint8_t transferOpFlag{};
uint16_t reqSizeBytes{};
uint16_t recordChangeNum{};
auto rc = decode_get_pdr_req(request, payloadLength, &recordHandle,
&dataTransferHandle, &transferOpFlag,
&reqSizeBytes, &recordChangeNum);
if (rc != PLDM_SUCCESS)
{
return CmdHandler::ccOnlyResponse(request, rc);
}
uint16_t respSizeBytes{};
uint8_t* recordData = nullptr;
try
{
pdr_utils::PdrEntry e;
auto record = pdr::getRecordByHandle(pdrRepo, recordHandle, e);
if (record == NULL)
{
return CmdHandler::ccOnlyResponse(
request, PLDM_PLATFORM_INVALID_RECORD_HANDLE);
}
if (reqSizeBytes)
{
respSizeBytes = e.size;
if (respSizeBytes > reqSizeBytes)
{
respSizeBytes = reqSizeBytes;
}
recordData = e.data;
}
response.resize(sizeof(pldm_msg_hdr) + PLDM_GET_PDR_MIN_RESP_BYTES +
respSizeBytes,
0);
responsePtr = reinterpret_cast<pldm_msg*>(response.data());
rc = encode_get_pdr_resp(
request->hdr.instance_id, PLDM_SUCCESS, e.handle.nextRecordHandle,
0, PLDM_START_AND_END, respSizeBytes, recordData, 0, responsePtr);
if (rc != PLDM_SUCCESS)
{
return ccOnlyResponse(request, rc);
}
}
catch (const std::exception& e)
{
std::cerr << "Error accessing PDR, HANDLE=" << recordHandle
<< " ERROR=" << e.what() << "\n";
return CmdHandler::ccOnlyResponse(request, PLDM_ERROR);
}
return response;
}
Response Handler::setStateEffecterStates(const pldm_msg* request,
size_t payloadLength)
{
Response response(
sizeof(pldm_msg_hdr) + PLDM_SET_STATE_EFFECTER_STATES_RESP_BYTES, 0);
auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
uint16_t effecterId;
uint8_t compEffecterCnt;
constexpr auto maxCompositeEffecterCnt = 8;
std::vector<set_effecter_state_field> stateField(maxCompositeEffecterCnt,
{0, 0});
if ((payloadLength > PLDM_SET_STATE_EFFECTER_STATES_REQ_BYTES) ||
(payloadLength < sizeof(effecterId) + sizeof(compEffecterCnt) +
sizeof(set_effecter_state_field)))
{
return CmdHandler::ccOnlyResponse(request, PLDM_ERROR_INVALID_LENGTH);
}
int rc = decode_set_state_effecter_states_req(request, payloadLength,
&effecterId, &compEffecterCnt,
stateField.data());
if (rc != PLDM_SUCCESS)
{
return CmdHandler::ccOnlyResponse(request, rc);
}
stateField.resize(compEffecterCnt);
const pldm::utils::DBusHandler dBusIntf;
rc = setStateEffecterStatesHandler<pldm::utils::DBusHandler>(
dBusIntf, effecterId, stateField);
if (rc != PLDM_SUCCESS)
{
return CmdHandler::ccOnlyResponse(request, rc);
}
rc = encode_set_state_effecter_states_resp(request->hdr.instance_id, rc,
responsePtr);
if (rc != PLDM_SUCCESS)
{
return ccOnlyResponse(request, rc);
}
return response;
}
} // namespace platform
} // namespace responder
} // namespace pldm