blob: ad9a019b0b43b61220f21de735750f93a79e11ab [file]
// 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_state.hpp"
#include "google3/host_commands.h"
#include "ec_util.hpp"
#include <stdplus/print.hpp>
#include <stdplus/raw.hpp>
#include <xyz/openbmc_project/Control/Hoth/State/error.hpp>
#include <chrono>
#include <cstdint>
#include <cstring>
#include <exception>
#include <functional>
#include <future>
namespace google
{
namespace hoth
{
namespace
{
constexpr std::chrono::minutes kTimerInterval = std::chrono::minutes(5);
template <typename T>
bool statisticsReponseHasEnoughWords(const ec_response_statistics& stats,
const T& field)
{
uint64_t offset_required =
(uint64_t)&field - (uint64_t)&stats + sizeof(field);
return stats.valid_words * 4 >= offset_required;
}
} // namespace
HothState::HothState(sdbusplus::bus::bus& bus, boost::asio::io_context& io,
const char* objPath, internal::HostCommand* hostCmd,
internal::EcUtil* ecutil,
const std::string& transport_type) :
HothStateObject(bus, objPath), bus(bus), io(io), hostCmd(hostCmd),
ecUtil(ecutil), timer(io)
{
// Update metrics immediately while kicking off the timer.
timerUpdateMetrics();
HothStateObject::transportType(transport_type);
}
void HothState::updateMetrics()
{
try
{
statistics = ecUtil->getHothStatistics();
// Emit the signal that property has changed.
// Fall back to default values if response does not contain enought
// words.
HothStateObject::resetFlags(
statisticsReponseHasEnoughWords(statistics,
statistics.hoth_reset_flags)
? (uint32_t)statistics.hoth_reset_flags
: 0);
HothStateObject::upTime(
statisticsReponseHasEnoughWords(statistics,
statistics.time_since_hoth_boot_us)
? (uint64_t)statistics.time_since_hoth_boot_us
: 0);
HothStateObject::roInfoStrikes(
statisticsReponseHasEnoughWords(statistics,
statistics.ro_info_strikes)
? (uint32_t)statistics.ro_info_strikes
: 0xffffffff);
HothStateObject::rwInfoStrikes(
statisticsReponseHasEnoughWords(statistics,
statistics.rw_info_strikes)
? (uint32_t)statistics.rw_info_strikes
: 0xffffffff);
HothStateObject::payloadUpdateFailureCode(
statisticsReponseHasEnoughWords(
statistics, statistics.payload_update_failure_reason)
? (uint16_t)statistics.payload_update_failure_reason
: 0xffff);
HothStateObject::payloadConfirmFailureCode(
statisticsReponseHasEnoughWords(
statistics,
statistics.payload_update_confirmation_cookie_failure_reason)
? (uint32_t)statistics
.payload_update_confirmation_cookie_failure_reason
: 0xffffffff);
HothStateObject::firmwareUpdateFailureCode(
statisticsReponseHasEnoughWords(
statistics, statistics.firmware_update_failure_reason)
? (uint16_t)statistics.firmware_update_failure_reason
: 0xffff);
HothStateObject::firmwareUpdateFailedMinor(
statisticsReponseHasEnoughWords(
statistics, statistics.failed_firmware_minor_version)
? (uint32_t)statistics.failed_firmware_minor_version
: 0xffffffff);
HothStateObject::bootloaderUpdateFailureCode(
statisticsReponseHasEnoughWords(statistics,
statistics.bootloader_update_error)
? (uint32_t)statistics.bootloader_update_error
: 0xffffffff);
}
catch (const std::exception& e)
{
stdplus::print(stderr,
"Fetching Hoth statistics had an exception: {}\n",
e.what());
}
try
{
ec_response_chip_info chip_info = ecUtil->getHothChipInfo();
std::ostringstream serial_number;
serial_number << chip_info.hardware_category << "-";
serial_number << std::setfill('0') << std::setw(16) << std::noshowbase
<< std::hex << chip_info.hardware_identity;
HothStateObject::chipSerialNumber(serial_number.str());
if (chip_info.hardware_category == 4)
{
HothStateObject::chipPartNumber("1100336");
HothStateObject::chipRevision("H1D3P");
}
else if (chip_info.hardware_category == 1 &&
chip_info.info_variant == 1)
{
HothStateObject::chipPartNumber("1059594");
HothStateObject::chipRevision("H1B3P");
}
else if (chip_info.hardware_category == 1)
{
HothStateObject::chipPartNumber("07138244");
HothStateObject::chipRevision("H1B2P");
}
else
{
HothStateObject::chipPartNumber("unknown");
HothStateObject::chipRevision("unknown");
}
}
catch (const std::exception& e)
{
stdplus::print(stderr, "Fetching Hoth chip info had an exception: {}\n",
e.what());
}
try
{
HothStateObject::hasPersistentPanicInfo(
ecUtil->checkHothPersistentPanicInfo());
}
catch (const std::exception& e)
{
stdplus::print(stderr,
"Fetching Hoth panic info had an exception: {}\n",
e.what());
}
try
{
ec_authz_record_get_response auth_record_resp =
ecUtil->getHothAuthRecord();
HothStateObject::hasValidAuthRecord(auth_record_resp.valid == 1);
if (auth_record_resp.valid == 1)
{
HothStateObject::authRecordCapabilities(
auth_record_resp.record.capabilities);
}
}
catch (const internal::CommandNotSupportedException& e)
{
// Do not log if unsupported
HothStateObject::hasValidAuthRecord(false);
}
catch (const std::exception& e)
{
stdplus::print(stderr,
"Fetching Hoth auth record had an exception: {}\n",
e.what());
HothStateObject::hasValidAuthRecord(false);
}
try
{
ec_response_key_rotation_status key_rotation_status =
ecUtil->getHothKeyRotationStatus();
HothStateObject::keyRotationVersion(key_rotation_status.version);
HothStateObject::keyRotationImageFamily(
key_rotation_status.image_family);
HothStateObject::keyRotationImageFamilyVariant(
key_rotation_status.image_family_variant);
HothStateObject::keyRotationValidationMethod(
key_rotation_status.validation_method);
HothStateObject::keyRotationValidationKeyData(
key_rotation_status.validation_key_data);
HothStateObject::keyRotationValidationHashData(
key_rotation_status.validation_hash_data);
}
catch (const internal::CommandNotSupportedException& e)
{
// Do not log if unsupported
HothStateObject::keyRotationValidationMethod(
KEY_ROTATION_VALIDATION_METHOD_GET_ERROR);
}
catch (const std::exception& e)
{
HothStateObject::keyRotationValidationMethod(
KEY_ROTATION_VALIDATION_METHOD_GET_ERROR);
stdplus::print(stderr,
"Fetching Hoth key rotation had an exception: {}\n",
e.what());
}
try
{
secure_boot_enforcement_state secure_boot_state =
ecUtil->getSecureBootEnforcementState();
HothStateObject::secureBootEnforced(secure_boot_state.enabled != 0);
}
catch (const internal::CommandNotSupportedException& e)
{
// Do not log if unsupported
HothStateObject::secureBootEnforced(false);
}
catch (const std::exception& e)
{
HothStateObject::secureBootEnforced(false);
stdplus::print(
stderr,
"Fetching Hoth secure boot enforcement had an exception: {}\n",
e.what());
}
try
{
payload_status_response payload_status = ecUtil->getPayloadStatus();
HothStateObject::payloadLockdownState(
payload_status.header.lockdown_state);
HothStateObject::payloadActivePartition(
payload_status.header.active_half);
if (payload_status.header.region_count >= 1)
{
HothStateObject::payloadValidationStateA(
payload_status.states[0].validation_state);
HothStateObject::payloadValidationFailureReasonA(
payload_status.states[0].failure_reason);
HothStateObject::payloadImageTypeA(
payload_status.states[0].image_type);
HothStateObject::payloadKeyIndexA(
payload_status.states[0].key_index);
HothStateObject::payloadImageFamilyA(
payload_status.states[0].image_family);
HothStateObject::payloadVersionA(
internal::payloadVersionString(payload_status.states[0]));
}
if (payload_status.header.region_count >= 2)
{
HothStateObject::payloadValidationStateB(
payload_status.states[1].validation_state);
HothStateObject::payloadValidationFailureReasonB(
payload_status.states[1].failure_reason);
HothStateObject::payloadImageTypeB(
payload_status.states[1].image_type);
HothStateObject::payloadKeyIndexB(
payload_status.states[1].key_index);
HothStateObject::payloadImageFamilyB(
payload_status.states[1].image_family);
HothStateObject::payloadVersionB(
internal::payloadVersionString(payload_status.states[1]));
}
}
catch (const internal::CommandNotSupportedException& e)
{
// Do not log if unsupported
}
catch (const std::exception& e)
{
stdplus::print(stderr,
"Fetching Hoth payload status had an exception: {}\n",
e.what());
}
}
void HothState::timerUpdateMetrics()
{
try
{
updateMetrics();
}
catch (const std::exception& e)
{
stdplus::print(stderr, "Fetching Hoth metrics had an exception: {}\n",
e.what());
}
timer.expires_after(kTimerInterval);
// NOLINTNEXTLINE(modernize-avoid-bind)
timer.async_wait(std::bind(&HothState::timerUpdateMetrics, this));
}
} // namespace hoth
} // namespace google