blob: ff6b3ef50db52a7a2fe5c37fe0f0aae33663e647 [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_state.hpp"
#include <chrono>
#include <cstdint>
#include <cstring>
#include <exception>
#include <functional>
#include <future>
#include <stdplus/print.hpp>
#include <stdplus/raw.hpp>
#include <xyz/openbmc_project/Control/Hoth/State/error.hpp>
#include "ec_util.hpp"
#include "google3/host_commands.h"
namespace google {
namespace hoth {
namespace {
constexpr uint32_t kTimerIntervalSeconds = 20;
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)
: HothStateObject(bus, objPath),
bus(bus),
io(io),
hostCmd(hostCmd),
ecUtil(ecutil),
timer(io) {
// Update metrics immediately while kicking off the timer.
timerUpdateMetrics();
}
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());
}
}
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(std::chrono::seconds(kTimerIntervalSeconds));
// NOLINTNEXTLINE(modernize-avoid-bind)
timer.async_wait(std::bind(&HothState::timerUpdateMetrics, this));
}
} // namespace hoth
} // namespace google