Hothd: Add support for querying authz record.
TESTED=gpaste/5916622332887040
Google-Bug-Id: 377507258
Change-Id: I54bb5a2f2f72e829cd742b786ac6dd1aaf79f3e9
Signed-off-by: Christian Kungler <ckungler@google.com>
diff --git a/ec_util.cpp b/ec_util.cpp
index 05bd01d..5098473 100644
--- a/ec_util.cpp
+++ b/ec_util.cpp
@@ -153,6 +153,20 @@
return matchPersistentPanicMagic(response_body);
}
+ec_authz_record_get_response EcUtilImpl::getHothAuthRecord() const {
+ ec_authz_record_get_request request = {
+ .index = 0,
+ .reserved = {},
+ };
+
+ std::vector<uint8_t> response = hostCmd->sendCommand(
+ EC_CMD_BOARD_SPECIFIC_BASE + EC_PRV_CMD_HOTH_GET_AUTHZ_RECORD,
+ kVersionZero, &request, sizeof(request));
+ std::span<const uint8_t> response_body = getResponseBody(response);
+
+ return stdplus::raw::copyFrom<ec_authz_record_get_response>(response_body);
+}
+
} // namespace internal
} // namespace hoth
diff --git a/ec_util.hpp b/ec_util.hpp
index 02cf6d5..b4b3061 100644
--- a/ec_util.hpp
+++ b/ec_util.hpp
@@ -45,6 +45,10 @@
// EC_PRV_CMD_HOTH_PERSISTENT_PANIC_INFO command.
bool checkHothPersistentPanicInfo() const override;
+ // Get the Hoth auth record.
+ // Only supports record id = 0, which is the only one currently used.
+ ec_authz_record_get_response getHothAuthRecord() const override;
+
private:
[[nodiscard]] static std::span<const uint8_t>
getResponseBody(std::vector<uint8_t> &response);
diff --git a/ec_util_interface.hpp b/ec_util_interface.hpp
index 3662c56..0cd9dd6 100644
--- a/ec_util_interface.hpp
+++ b/ec_util_interface.hpp
@@ -39,6 +39,8 @@
// Check the presence of Hoth peresistent panic info by issuing a single
// EC_PRV_CMD_HOTH_PERSISTENT_PANIC_INFO command.
virtual bool checkHothPersistentPanicInfo() const = 0;
+
+ virtual ec_authz_record_get_response getHothAuthRecord() const = 0;
};
} // namespace internal
diff --git a/google3/host_commands.h b/google3/host_commands.h
index 15f1c1e..11f952a 100644
--- a/google3/host_commands.h
+++ b/google3/host_commands.h
@@ -566,4 +566,48 @@
// followed by the requested bytes.
} __attribute__((aligned(4)));
+#define EC_PRV_CMD_HOTH_GET_AUTHZ_RECORD 0x0018
+
+struct ec_authz_record_get_request {
+ // Authorization record index to get. Currently only index=0 is
+ // supported.
+ uint8_t index;
+ uint8_t reserved[3];
+} __attribute__((packed));
+
+
+#define AUTHORIZATION_RECORD_MAGIC_SIZE 8
+#define AUTHORIZATION_RECORD_SIGNATURE_SIZE (96 * 4)
+#define AUTHORIZATION_RECORD_FAUX_FUSES_SIZE 4
+#define AUTHORIZATION_RECORD_NONCE_SIZE 32
+
+// All multi-byte fields are little endian.
+struct authorization_record {
+ uint8_t magic[AUTHORIZATION_RECORD_MAGIC_SIZE];
+ little_uint32_t signature[AUTHORIZATION_RECORD_SIGNATURE_SIZE / sizeof(uint32_t)];
+ little_uint32_t version;
+ little_uint32_t reserved_0;
+ little_uint32_t size;
+ little_uint32_t key_id;
+ little_uint32_t flags;
+ uint8_t faux_fuses[AUTHORIZATION_RECORD_FAUX_FUSES_SIZE];
+ little_uint64_t capabilities;
+ little_uint32_t dev_id_0;
+ little_uint32_t dev_id_1;
+ little_uint32_t
+ authorization_nonce[AUTHORIZATION_RECORD_NONCE_SIZE / sizeof(uint32_t)];
+} __attribute__((aligned(4)));
+
+struct ec_authz_record_get_response {
+ // Index of authorization record in the response. This value matches the
+ // `index` in the corresponding host command request.
+ uint8_t index;
+
+ // When `valid` is non-zero value, the `record` at `index` in this
+ // response is valid.
+ uint8_t valid;
+ uint8_t reserved[2];
+ struct authorization_record record;
+} __attribute__((aligned(4)));
+
#endif /* __PRIVATE_CR51_INCLUDE_CR51_HOST_COMMANDS_H */
diff --git a/hoth_state.cpp b/hoth_state.cpp
index aead187..b63d77c 100644
--- a/hoth_state.cpp
+++ b/hoth_state.cpp
@@ -60,56 +60,86 @@
void HothState::updateMetrics()
{
- statistics = ecUtil->getHothStatistics();
+ 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);
+ // 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());
+ }
- HothStateObject::hasPersistentPanicInfo(
- ecUtil->checkHothPersistentPanicInfo());
+ 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 std::exception& e)
+ {
+ stdplus::print(stderr, "Fetching Hoth auth record had an exception: {}\n",
+ e.what());
+ }
}
void HothState::timerUpdateMetrics()
diff --git a/test/ec_util_mock.hpp b/test/ec_util_mock.hpp
index 0f689cf..21d0e63 100644
--- a/test/ec_util_mock.hpp
+++ b/test/ec_util_mock.hpp
@@ -32,6 +32,7 @@
public:
MOCK_CONST_METHOD0(getHothStatistics, ec_response_statistics());
MOCK_CONST_METHOD0(checkHothPersistentPanicInfo, bool());
+ MOCK_CONST_METHOD0(getHothAuthRecord, ec_authz_record_get_response());
};
} // namespace internal
diff --git a/test/hoth_state_unittest.cpp b/test/hoth_state_unittest.cpp
index 07ade6b..d803d75 100644
--- a/test/hoth_state_unittest.cpp
+++ b/test/hoth_state_unittest.cpp
@@ -100,6 +100,26 @@
EXPECT_FALSE(hoth_state->hasPersistentPanicInfo());
}
+TEST_F(HothStateTest, ValidAuthRecord)
+{
+ ec_authz_record_get_response response = {};
+ response.valid = 1;
+ response.record.capabilities = 0x0102030405060708;
+ EXPECT_CALL(ecUtil, getHothAuthRecord()).WillOnce(Return(response));
+ EXPECT_NO_THROW(hoth_state->updateMetrics());
+ EXPECT_TRUE(hoth_state->hasValidAuthRecord());
+ EXPECT_EQ(hoth_state->authRecordCapabilities(), 0x0102030405060708);
+}
+
+TEST_F(HothStateTest, InvalidAuthRecord)
+{
+ ec_authz_record_get_response response = {};
+ response.valid = 0;
+ EXPECT_CALL(ecUtil, getHothAuthRecord()).WillOnce(Return(response));
+ EXPECT_NO_THROW(hoth_state->updateMetrics());
+ EXPECT_FALSE(hoth_state->hasValidAuthRecord());
+}
+
ec_response_statistics getMockStatistics()
{
ec_response_statistics ret = {
diff --git a/yaml/xyz/openbmc_project/Control/Hoth/State.interface.yaml b/yaml/xyz/openbmc_project/Control/Hoth/State.interface.yaml
index 6da82ae..f3cc258 100644
--- a/yaml/xyz/openbmc_project/Control/Hoth/State.interface.yaml
+++ b/yaml/xyz/openbmc_project/Control/Hoth/State.interface.yaml
@@ -113,3 +113,21 @@
- readonly
description: >
Whether the Hoth device has a persistent panic record stored.
+
+ - name: HasValidAuthRecord
+ type: boolean
+ default: false
+ flags:
+ - readonly
+ description: >
+ Whether the Hoth device has a valid auth record.
+
+ - name: AuthRecordCapabilities
+ type: uint64
+ default: 0
+ flags:
+ - readonly
+ description: >
+ A bitfield of enabled Auth record capabilities.
+ errors:
+ - self.Error.ExpectedInfoNotFound