blob: bdb3c2bc987872dfe581eae4afdb8d02e63683d4 [file] [log] [blame]
// Copyright 2024 Google LLC
//
// 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 "hoth_util_impl.hpp"
#include <google3/g_ec_commands.h>
#include <google3/host_commands.h>
#include <boost/endian/conversion.hpp>
#include <phosphor-logging/log.hpp>
#include <stdplus/raw.hpp>
#include <xyz/openbmc_project/Control/Hoth/error.hpp>
#include <cstdint>
#include <limits>
#include <memory>
#include <span>
#include <vector>
using CommandFailure =
sdbusplus::xyz::openbmc_project::Control::Hoth::Error::CommandFailure;
using ResponseFailure =
sdbusplus::xyz::openbmc_project::Control::Hoth::Error::ResponseFailure;
namespace ipmi_hoth
{
namespace internal
{
using namespace phosphor::logging;
std::vector<uint8_t>
HothUtilImpl::wrapECSKMHSSRequest(std::span<const uint8_t> request)
{
// Populate EC request header based on the request
g_ec_host_request skmHssHeader = {
/*struct_version*/ G_EC_HOST_REQUEST_VERSION,
/*checksum*/ 0,
/*command*/ G_EC_PRIVATE_HOST_COMMAND_VALUE(EC_PRV_CMD_HOTH_SKM_HSS),
/*command_version*/ 0,
/*reserved*/ 0,
/*data_len*/ static_cast<uint16_t>(request.size())};
boost::endian::native_to_little_inplace(skmHssHeader);
skmHssHeader.checksum -=
calculateChecksum(stdplus::raw::asSpan<uint8_t>(skmHssHeader), request);
// Concatenate the request header and the request into one uint8_t vector to
// be sent to EC
const auto requestHeaderPtr = reinterpret_cast<uint8_t*>(&skmHssHeader);
std::vector<uint8_t> hothCommand(requestHeaderPtr,
requestHeaderPtr + sizeof(skmHssHeader));
hothCommand.insert(hothCommand.end(), request.begin(), request.end());
return hothCommand;
}
std::vector<uint8_t> HothUtilImpl::readSKMHSS(uint32_t slot)
{
struct ec_request_skm_hss request = {};
request.operation = SKM_HSS_READ;
request.slot = slot;
return wrapECSKMHSSRequest(stdplus::raw::asSpan<const uint8_t>(request));
}
std::vector<uint8_t>
HothUtilImpl::writeSKMHSS(uint32_t slot, std::span<const uint8_t> data)
{
if (data.empty() || data.size() > SKM_HSS_STRUCT_SIZE)
{
log<level::ERR>("Bad HSS payload size",
entry("REQ_SIZE=%lu SKM_HSS_SIZE=%lu",
static_cast<unsigned long>(data.size()),
static_cast<unsigned long>(SKM_HSS_STRUCT_SIZE)));
throw CommandFailure();
}
struct ec_request_skm_hss request = {};
request.operation = SKM_HSS_WRITE;
request.slot = slot;
std::memcpy(request.payload.data, data.data(), data.size());
return wrapECSKMHSSRequest(stdplus::raw::asSpan<const uint8_t>(request));
}
std::vector<uint8_t> HothUtilImpl::deleteSKMHSS(uint32_t slot)
{
struct ec_request_skm_hss request = {};
request.operation = SKM_HSS_DELETE;
request.slot = slot;
return wrapECSKMHSSRequest(stdplus::raw::asSpan<const uint8_t>(request));
}
std::span<const uint8_t>
HothUtilImpl::payloadECResponse(std::span<const uint8_t> rsp)
{
g_ec_host_response header{};
if (rsp.size() < sizeof(header))
{
log<level::ERR>("Response is too short",
entry("LENGTH=%d", rsp.size()));
throw ResponseFailure();
}
std::memcpy(&header, rsp.data(), sizeof(header));
boost::endian::native_to_little_inplace(header);
if (header.struct_version != G_EC_HOST_RESPONSE_VERSION)
{
log<level::ERR>(
"Unsupported stuct_version in response",
entry("VERSION=%d", static_cast<uint8_t>(header.struct_version)));
throw ResponseFailure();
}
if (header.result != EC_RES_SUCCESS && header.result != EC_RES_UNAVAILABLE)
{
log<level::ERR>(
"Unexpected return code",
entry("RESULT=%d", static_cast<uint16_t>(header.result)));
throw ResponseFailure();
}
return rsp.last(rsp.size() - sizeof(header));
}
} // namespace internal
} // namespace ipmi_hoth