| // 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 |