blob: 7643ea9d9a14ece7463c6ef14bc9e7ca8f8bf33f [file] [log] [blame]
// Copyright lowRISC contributors.
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Identifier: Apache-2.0
#include "sw/device/lib/dif/dif_otp_ctrl.h"
#include <cstring>
#include <limits>
#include <ostream>
#include "gtest/gtest.h"
#include "sw/device/lib/base/mmio.h"
#include "sw/device/lib/base/mock_mmio.h"
#include "sw/device/lib/dif/dif_test_base.h"
#include "otp_ctrl_regs.h" // Generated.
namespace dif_otp_ctrl_unittest {
namespace {
using ::mock_mmio::LeInt;
using ::mock_mmio::MmioTest;
using ::mock_mmio::MockDevice;
using ::testing::Each;
using ::testing::ElementsAre;
class OtpTest : public testing::Test, public MmioTest {
protected:
dif_otp_ctrl_t otp_ = {.base_addr = dev().region()};
};
class ConfigTest : public OtpTest {};
TEST_F(ConfigTest, Basic) {
dif_otp_ctrl_config_t config = {
.check_timeout = 100'000,
.integrity_period_mask = 0x3'ffff,
.consistency_period_mask = 0x3ff'ffff,
};
EXPECT_READ32(OTP_CTRL_CHECK_REGWEN_REG_OFFSET,
{{OTP_CTRL_CHECK_REGWEN_CHECK_REGWEN_BIT, true}});
EXPECT_WRITE32(OTP_CTRL_CHECK_TIMEOUT_REG_OFFSET, config.check_timeout);
EXPECT_WRITE32(OTP_CTRL_INTEGRITY_CHECK_PERIOD_REG_OFFSET,
config.integrity_period_mask);
EXPECT_WRITE32(OTP_CTRL_CONSISTENCY_CHECK_PERIOD_REG_OFFSET,
config.consistency_period_mask);
EXPECT_DIF_OK(dif_otp_ctrl_configure(&otp_, config));
}
TEST_F(ConfigTest, Locked) {
EXPECT_READ32(OTP_CTRL_CHECK_REGWEN_REG_OFFSET,
{{OTP_CTRL_CHECK_REGWEN_CHECK_REGWEN_BIT, false}});
EXPECT_EQ(dif_otp_ctrl_configure(&otp_, {}), kDifLocked);
}
TEST_F(ConfigTest, IsConfigLocked) {
bool flag;
EXPECT_READ32(OTP_CTRL_CHECK_REGWEN_REG_OFFSET,
{{OTP_CTRL_CHECK_REGWEN_CHECK_REGWEN_BIT, true}});
EXPECT_DIF_OK(dif_otp_ctrl_config_is_locked(&otp_, &flag));
EXPECT_FALSE(flag);
EXPECT_READ32(OTP_CTRL_CHECK_REGWEN_REG_OFFSET,
{{OTP_CTRL_CHECK_REGWEN_CHECK_REGWEN_BIT, false}});
EXPECT_DIF_OK(dif_otp_ctrl_config_is_locked(&otp_, &flag));
EXPECT_TRUE(flag);
}
TEST_F(ConfigTest, LockConfig) {
EXPECT_WRITE32(OTP_CTRL_CHECK_REGWEN_REG_OFFSET,
{{OTP_CTRL_CHECK_REGWEN_CHECK_REGWEN_BIT, false}});
EXPECT_DIF_OK(dif_otp_ctrl_lock_config(&otp_));
}
TEST_F(ConfigTest, NullArgs) {
EXPECT_DIF_BADARG(dif_otp_ctrl_configure(nullptr, {}));
bool flag;
EXPECT_DIF_BADARG(dif_otp_ctrl_config_is_locked(nullptr, &flag));
EXPECT_DIF_BADARG(dif_otp_ctrl_config_is_locked(&otp_, nullptr));
EXPECT_DIF_BADARG(dif_otp_ctrl_lock_config(nullptr));
}
class CheckTest : public OtpTest {};
TEST_F(CheckTest, Integrity) {
EXPECT_READ32(
OTP_CTRL_CHECK_TRIGGER_REGWEN_REG_OFFSET,
{{OTP_CTRL_CHECK_TRIGGER_REGWEN_CHECK_TRIGGER_REGWEN_BIT, true}});
EXPECT_WRITE32(OTP_CTRL_CHECK_TRIGGER_REG_OFFSET,
{{OTP_CTRL_CHECK_TRIGGER_INTEGRITY_BIT, true}});
EXPECT_DIF_OK(dif_otp_ctrl_check_integrity(&otp_));
}
TEST_F(CheckTest, Consistency) {
EXPECT_READ32(
OTP_CTRL_CHECK_TRIGGER_REGWEN_REG_OFFSET,
{{OTP_CTRL_CHECK_TRIGGER_REGWEN_CHECK_TRIGGER_REGWEN_BIT, true}});
EXPECT_WRITE32(OTP_CTRL_CHECK_TRIGGER_REG_OFFSET,
{{OTP_CTRL_CHECK_TRIGGER_CONSISTENCY_BIT, true}});
EXPECT_DIF_OK(dif_otp_ctrl_check_consistency(&otp_));
}
TEST_F(CheckTest, LockTrigger) {
EXPECT_WRITE32(
OTP_CTRL_CHECK_TRIGGER_REGWEN_REG_OFFSET,
{{OTP_CTRL_CHECK_TRIGGER_REGWEN_CHECK_TRIGGER_REGWEN_BIT, false}});
EXPECT_DIF_OK(dif_otp_ctrl_lock_check_trigger(&otp_));
}
TEST_F(CheckTest, Locked) {
EXPECT_READ32(
OTP_CTRL_CHECK_TRIGGER_REGWEN_REG_OFFSET,
{{OTP_CTRL_CHECK_TRIGGER_REGWEN_CHECK_TRIGGER_REGWEN_BIT, false}});
EXPECT_EQ(dif_otp_ctrl_check_integrity(&otp_), kDifLocked);
EXPECT_READ32(
OTP_CTRL_CHECK_TRIGGER_REGWEN_REG_OFFSET,
{{OTP_CTRL_CHECK_TRIGGER_REGWEN_CHECK_TRIGGER_REGWEN_BIT, false}});
EXPECT_EQ(dif_otp_ctrl_check_consistency(&otp_), kDifLocked);
}
TEST_F(CheckTest, NullArgs) {
EXPECT_DIF_BADARG(dif_otp_ctrl_check_integrity(nullptr));
EXPECT_DIF_BADARG(dif_otp_ctrl_check_consistency(nullptr));
}
class ReadLockTest : public OtpTest {};
TEST_F(ReadLockTest, IsLocked) {
bool flag;
EXPECT_READ32(
OTP_CTRL_CREATOR_SW_CFG_READ_LOCK_REG_OFFSET,
{{OTP_CTRL_CREATOR_SW_CFG_READ_LOCK_CREATOR_SW_CFG_READ_LOCK_BIT, true}});
EXPECT_DIF_OK(dif_otp_ctrl_reading_is_locked(
&otp_, kDifOtpCtrlPartitionCreatorSwCfg, &flag));
EXPECT_FALSE(flag);
EXPECT_READ32(
OTP_CTRL_CREATOR_SW_CFG_READ_LOCK_REG_OFFSET,
{{OTP_CTRL_CREATOR_SW_CFG_READ_LOCK_CREATOR_SW_CFG_READ_LOCK_BIT,
false}});
EXPECT_DIF_OK(dif_otp_ctrl_reading_is_locked(
&otp_, kDifOtpCtrlPartitionCreatorSwCfg, &flag));
EXPECT_TRUE(flag);
EXPECT_READ32(
OTP_CTRL_OWNER_SW_CFG_READ_LOCK_REG_OFFSET,
{{OTP_CTRL_CREATOR_SW_CFG_READ_LOCK_CREATOR_SW_CFG_READ_LOCK_BIT, true}});
EXPECT_DIF_OK(dif_otp_ctrl_reading_is_locked(
&otp_, kDifOtpCtrlPartitionOwnerSwCfg, &flag));
EXPECT_FALSE(flag);
EXPECT_READ32(
OTP_CTRL_OWNER_SW_CFG_READ_LOCK_REG_OFFSET,
{{OTP_CTRL_CREATOR_SW_CFG_READ_LOCK_CREATOR_SW_CFG_READ_LOCK_BIT,
false}});
EXPECT_DIF_OK(dif_otp_ctrl_reading_is_locked(
&otp_, kDifOtpCtrlPartitionOwnerSwCfg, &flag));
EXPECT_TRUE(flag);
}
TEST_F(ReadLockTest, Lock) {
EXPECT_READ32(OTP_CTRL_DIRECT_ACCESS_REGWEN_REG_OFFSET, 1);
EXPECT_WRITE32(
OTP_CTRL_VENDOR_TEST_READ_LOCK_REG_OFFSET,
{{OTP_CTRL_VENDOR_TEST_READ_LOCK_VENDOR_TEST_READ_LOCK_BIT, false}});
EXPECT_DIF_OK(
dif_otp_ctrl_lock_reading(&otp_, kDifOtpCtrlPartitionVendorTest));
EXPECT_READ32(OTP_CTRL_DIRECT_ACCESS_REGWEN_REG_OFFSET, 1);
EXPECT_WRITE32(
OTP_CTRL_CREATOR_SW_CFG_READ_LOCK_REG_OFFSET,
{{OTP_CTRL_CREATOR_SW_CFG_READ_LOCK_CREATOR_SW_CFG_READ_LOCK_BIT,
false}});
EXPECT_DIF_OK(
dif_otp_ctrl_lock_reading(&otp_, kDifOtpCtrlPartitionCreatorSwCfg));
EXPECT_READ32(OTP_CTRL_DIRECT_ACCESS_REGWEN_REG_OFFSET, 1);
EXPECT_WRITE32(
OTP_CTRL_OWNER_SW_CFG_READ_LOCK_REG_OFFSET,
{{OTP_CTRL_OWNER_SW_CFG_READ_LOCK_OWNER_SW_CFG_READ_LOCK_BIT, false}});
EXPECT_DIF_OK(
dif_otp_ctrl_lock_reading(&otp_, kDifOtpCtrlPartitionOwnerSwCfg));
}
TEST_F(ReadLockTest, HwPartition) {
bool flag;
EXPECT_DIF_BADARG(
dif_otp_ctrl_lock_reading(&otp_, kDifOtpCtrlPartitionHwCfg));
EXPECT_DIF_BADARG(dif_otp_ctrl_reading_is_locked(
&otp_, kDifOtpCtrlPartitionSecret0, &flag));
}
TEST_F(ReadLockTest, NullArgs) {
bool flag;
EXPECT_DIF_BADARG(dif_otp_ctrl_reading_is_locked(
nullptr, kDifOtpCtrlPartitionOwnerSwCfg, &flag));
EXPECT_DIF_BADARG(dif_otp_ctrl_reading_is_locked(
&otp_, kDifOtpCtrlPartitionOwnerSwCfg, nullptr));
EXPECT_DIF_BADARG(
dif_otp_ctrl_lock_reading(nullptr, kDifOtpCtrlPartitionOwnerSwCfg));
}
class StatusTest : public OtpTest {};
TEST_F(StatusTest, Idle) {
dif_otp_ctrl_status_t status;
EXPECT_READ32(OTP_CTRL_STATUS_REG_OFFSET,
{{OTP_CTRL_STATUS_DAI_IDLE_BIT, true}});
EXPECT_READ32(OTP_CTRL_ERR_CODE_REG_OFFSET, 0);
EXPECT_DIF_OK(dif_otp_ctrl_get_status(&otp_, &status));
EXPECT_EQ(status.codes, 1 << kDifOtpCtrlStatusCodeDaiIdle);
EXPECT_THAT(status.causes, Each(kDifOtpCtrlErrorOk));
}
TEST_F(StatusTest, Errors) {
dif_otp_ctrl_status_t status;
EXPECT_READ32(OTP_CTRL_STATUS_REG_OFFSET,
{
{OTP_CTRL_STATUS_DAI_IDLE_BIT, true},
{OTP_CTRL_STATUS_HW_CFG_ERROR_BIT, true},
{OTP_CTRL_STATUS_LCI_ERROR_BIT, true},
});
EXPECT_READ32(OTP_CTRL_ERR_CODE_REG_OFFSET,
{{OTP_CTRL_ERR_CODE_ERR_CODE_3_OFFSET,
OTP_CTRL_ERR_CODE_ERR_CODE_0_VALUE_MACRO_ECC_CORR_ERROR},
{OTP_CTRL_ERR_CODE_ERR_CODE_9_OFFSET,
OTP_CTRL_ERR_CODE_ERR_CODE_0_VALUE_MACRO_ERROR}});
EXPECT_DIF_OK(dif_otp_ctrl_get_status(&otp_, &status));
EXPECT_EQ(status.codes, (1 << kDifOtpCtrlStatusCodeDaiIdle) |
(1 << kDifOtpCtrlStatusCodeHwCfgError) |
(1 << kDifOtpCtrlStatusCodeLciError));
EXPECT_EQ(status.causes[kDifOtpCtrlStatusCodeHwCfgError],
kDifOtpCtrlErrorMacroRecoverableRead);
EXPECT_EQ(status.causes[kDifOtpCtrlStatusCodeLciError],
kDifOtpCtrlErrorMacroUnspecified);
}
TEST_F(StatusTest, NullArgs) {
dif_otp_ctrl_status_t status;
EXPECT_DIF_BADARG(dif_otp_ctrl_get_status(nullptr, &status));
EXPECT_DIF_BADARG(dif_otp_ctrl_get_status(&otp_, nullptr));
}
class DaiReadTest : public OtpTest {};
TEST_F(DaiReadTest, Read32) {
EXPECT_READ32(
OTP_CTRL_DIRECT_ACCESS_REGWEN_REG_OFFSET,
{{OTP_CTRL_DIRECT_ACCESS_REGWEN_DIRECT_ACCESS_REGWEN_BIT, true}});
EXPECT_WRITE32(OTP_CTRL_DIRECT_ACCESS_ADDRESS_REG_OFFSET,
OTP_CTRL_PARAM_MANUF_STATE_OFFSET);
EXPECT_WRITE32(OTP_CTRL_DIRECT_ACCESS_CMD_REG_OFFSET,
{{OTP_CTRL_DIRECT_ACCESS_CMD_RD_BIT, true}});
EXPECT_DIF_OK(dif_otp_ctrl_dai_read_start(&otp_, kDifOtpCtrlPartitionHwCfg,
/*address=*/0x20));
EXPECT_READ32(
OTP_CTRL_DIRECT_ACCESS_REGWEN_REG_OFFSET,
{{OTP_CTRL_DIRECT_ACCESS_REGWEN_DIRECT_ACCESS_REGWEN_BIT, true}});
EXPECT_READ32(OTP_CTRL_DIRECT_ACCESS_RDATA_0_REG_OFFSET, 0x12345678);
uint32_t val;
EXPECT_DIF_OK(dif_otp_ctrl_dai_read32_end(&otp_, &val));
EXPECT_EQ(val, 0x12345678);
}
TEST_F(DaiReadTest, Read64) {
EXPECT_READ32(
OTP_CTRL_DIRECT_ACCESS_REGWEN_REG_OFFSET,
{{OTP_CTRL_DIRECT_ACCESS_REGWEN_DIRECT_ACCESS_REGWEN_BIT, true}});
EXPECT_WRITE32(OTP_CTRL_DIRECT_ACCESS_ADDRESS_REG_OFFSET,
OTP_CTRL_PARAM_SECRET2_OFFSET + 0x8);
EXPECT_WRITE32(OTP_CTRL_DIRECT_ACCESS_CMD_REG_OFFSET,
{{OTP_CTRL_DIRECT_ACCESS_CMD_RD_BIT, true}});
EXPECT_DIF_OK(dif_otp_ctrl_dai_read_start(&otp_, kDifOtpCtrlPartitionSecret2,
/*address=*/0x8));
EXPECT_READ32(
OTP_CTRL_DIRECT_ACCESS_REGWEN_REG_OFFSET,
{{OTP_CTRL_DIRECT_ACCESS_REGWEN_DIRECT_ACCESS_REGWEN_BIT, true}});
EXPECT_READ32(OTP_CTRL_DIRECT_ACCESS_RDATA_1_REG_OFFSET, 0x12345678);
EXPECT_READ32(OTP_CTRL_DIRECT_ACCESS_RDATA_0_REG_OFFSET, 0x90abcdef);
uint64_t val;
EXPECT_DIF_OK(dif_otp_ctrl_dai_read64_end(&otp_, &val));
EXPECT_EQ(val, 0x1234567890abcdef);
}
TEST_F(DaiReadTest, Unaligned) {
EXPECT_EQ(dif_otp_ctrl_dai_read_start(&otp_, kDifOtpCtrlPartitionHwCfg,
/*address=*/0b01),
kDifUnaligned);
EXPECT_EQ(dif_otp_ctrl_dai_read_start(&otp_, kDifOtpCtrlPartitionSecret2,
/*address=*/0b100),
kDifUnaligned);
}
TEST_F(DaiReadTest, OutOfRange) {
EXPECT_EQ(dif_otp_ctrl_dai_read_start(&otp_, kDifOtpCtrlPartitionHwCfg,
/*address=*/0x100),
kDifOutOfRange);
}
TEST_F(DaiReadTest, Busy) {
EXPECT_READ32(
OTP_CTRL_DIRECT_ACCESS_REGWEN_REG_OFFSET,
{{OTP_CTRL_DIRECT_ACCESS_REGWEN_DIRECT_ACCESS_REGWEN_BIT, false}});
EXPECT_EQ(dif_otp_ctrl_dai_read_start(&otp_, kDifOtpCtrlPartitionHwCfg,
/*address=*/0x0),
kDifUnavailable);
EXPECT_READ32(
OTP_CTRL_DIRECT_ACCESS_REGWEN_REG_OFFSET,
{{OTP_CTRL_DIRECT_ACCESS_REGWEN_DIRECT_ACCESS_REGWEN_BIT, false}});
uint32_t val32;
EXPECT_EQ(dif_otp_ctrl_dai_read32_end(&otp_, &val32), kDifUnavailable);
EXPECT_READ32(
OTP_CTRL_DIRECT_ACCESS_REGWEN_REG_OFFSET,
{{OTP_CTRL_DIRECT_ACCESS_REGWEN_DIRECT_ACCESS_REGWEN_BIT, false}});
uint64_t val64;
EXPECT_EQ(dif_otp_ctrl_dai_read64_end(&otp_, &val64), kDifUnavailable);
}
TEST_F(DaiReadTest, NullArgs) {
EXPECT_DIF_BADARG(dif_otp_ctrl_dai_read_start(nullptr,
kDifOtpCtrlPartitionHwCfg,
/*address=*/0x0));
uint32_t val32;
EXPECT_DIF_BADARG(dif_otp_ctrl_dai_read32_end(nullptr, &val32));
EXPECT_DIF_BADARG(dif_otp_ctrl_dai_read32_end(&otp_, nullptr));
uint64_t val64;
EXPECT_DIF_BADARG(dif_otp_ctrl_dai_read64_end(nullptr, &val64));
EXPECT_DIF_BADARG(dif_otp_ctrl_dai_read64_end(&otp_, nullptr));
}
class DaiProgramTest : public OtpTest {};
TEST_F(DaiProgramTest, Program32) {
EXPECT_READ32(
OTP_CTRL_DIRECT_ACCESS_REGWEN_REG_OFFSET,
{{OTP_CTRL_DIRECT_ACCESS_REGWEN_DIRECT_ACCESS_REGWEN_BIT, true}});
EXPECT_WRITE32(OTP_CTRL_DIRECT_ACCESS_ADDRESS_REG_OFFSET,
OTP_CTRL_PARAM_MANUF_STATE_OFFSET);
EXPECT_WRITE32(OTP_CTRL_DIRECT_ACCESS_WDATA_0_REG_OFFSET, 0x12345678);
EXPECT_WRITE32(OTP_CTRL_DIRECT_ACCESS_CMD_REG_OFFSET,
{{OTP_CTRL_DIRECT_ACCESS_CMD_WR_BIT, true}});
EXPECT_DIF_OK(dif_otp_ctrl_dai_program32(&otp_, kDifOtpCtrlPartitionHwCfg,
/*address=*/0x20,
/*value=*/0x12345678));
}
TEST_F(DaiProgramTest, Program64) {
EXPECT_READ32(
OTP_CTRL_DIRECT_ACCESS_REGWEN_REG_OFFSET,
{{OTP_CTRL_DIRECT_ACCESS_REGWEN_DIRECT_ACCESS_REGWEN_BIT, true}});
EXPECT_WRITE32(OTP_CTRL_DIRECT_ACCESS_ADDRESS_REG_OFFSET,
OTP_CTRL_PARAM_SECRET2_OFFSET + 0x8);
EXPECT_WRITE32(OTP_CTRL_DIRECT_ACCESS_WDATA_0_REG_OFFSET, 0x90abcdef);
EXPECT_WRITE32(OTP_CTRL_DIRECT_ACCESS_WDATA_1_REG_OFFSET, 0x12345678);
EXPECT_WRITE32(OTP_CTRL_DIRECT_ACCESS_CMD_REG_OFFSET,
{{OTP_CTRL_DIRECT_ACCESS_CMD_WR_BIT, true}});
EXPECT_DIF_OK(dif_otp_ctrl_dai_program64(&otp_, kDifOtpCtrlPartitionSecret2,
/*address=*/0x8,
/*value=*/0x1234567890abcdef));
}
TEST_F(DaiProgramTest, BadPartition) {
EXPECT_EQ(dif_otp_ctrl_dai_program32(&otp_, kDifOtpCtrlPartitionSecret1,
/*address=*/0x0, /*value=*/42),
kDifError);
EXPECT_EQ(dif_otp_ctrl_dai_program64(&otp_, kDifOtpCtrlPartitionHwCfg,
/*address=*/0x0, /*value=*/42),
kDifError);
// LC is never writeable.
EXPECT_EQ(dif_otp_ctrl_dai_program32(&otp_, kDifOtpCtrlPartitionLifeCycle,
/*address=*/0x0, /*value=*/42),
kDifError);
}
TEST_F(DaiProgramTest, Unaligned) {
EXPECT_EQ(dif_otp_ctrl_dai_program32(&otp_, kDifOtpCtrlPartitionHwCfg,
/*address=*/0b01, /*value=*/42),
kDifUnaligned);
EXPECT_EQ(dif_otp_ctrl_dai_program64(&otp_, kDifOtpCtrlPartitionSecret2,
/*address=*/0b100, /*value=*/42),
kDifUnaligned);
}
TEST_F(DaiProgramTest, OutOfRange) {
// Check that we can't write a digest directly.
EXPECT_EQ(dif_otp_ctrl_dai_program32(
&otp_, kDifOtpCtrlPartitionCreatorSwCfg,
/*address=*/OTP_CTRL_PARAM_CREATOR_SW_CFG_DIGEST_OFFSET,
/*value=*/42),
kDifOutOfRange);
// Same digest check for 64-bit.
EXPECT_EQ(dif_otp_ctrl_dai_program64(
&otp_, kDifOtpCtrlPartitionSecret2,
/*address=*/OTP_CTRL_PARAM_SECRET2_DIGEST_OFFSET, /*value=*/42),
kDifOutOfRange);
}
TEST_F(DaiProgramTest, Busy) {
EXPECT_READ32(
OTP_CTRL_DIRECT_ACCESS_REGWEN_REG_OFFSET,
{{OTP_CTRL_DIRECT_ACCESS_REGWEN_DIRECT_ACCESS_REGWEN_BIT, false}});
EXPECT_EQ(dif_otp_ctrl_dai_program32(&otp_, kDifOtpCtrlPartitionHwCfg,
/*address=*/0x0, /*value=*/42),
kDifUnavailable);
EXPECT_READ32(
OTP_CTRL_DIRECT_ACCESS_REGWEN_REG_OFFSET,
{{OTP_CTRL_DIRECT_ACCESS_REGWEN_DIRECT_ACCESS_REGWEN_BIT, false}});
EXPECT_EQ(dif_otp_ctrl_dai_program64(&otp_, kDifOtpCtrlPartitionSecret0,
/*address=*/0x0, /*value=*/42),
kDifUnavailable);
}
TEST_F(DaiProgramTest, NullArgs) {
EXPECT_DIF_BADARG(dif_otp_ctrl_dai_program32(nullptr,
kDifOtpCtrlPartitionHwCfg,
/*address=*/0x0, /*value=*/42));
EXPECT_DIF_BADARG(dif_otp_ctrl_dai_program64(nullptr,
kDifOtpCtrlPartitionSecret0,
/*address=*/0x0, /*value=*/42));
}
class DaiDigestTest : public OtpTest {};
TEST_F(DaiDigestTest, DigestSw) {
EXPECT_READ32(
OTP_CTRL_DIRECT_ACCESS_REGWEN_REG_OFFSET,
{{OTP_CTRL_DIRECT_ACCESS_REGWEN_DIRECT_ACCESS_REGWEN_BIT, true}});
EXPECT_WRITE32(OTP_CTRL_DIRECT_ACCESS_ADDRESS_REG_OFFSET,
OTP_CTRL_PARAM_CREATOR_SW_CFG_DIGEST_OFFSET);
EXPECT_WRITE32(OTP_CTRL_DIRECT_ACCESS_WDATA_0_REG_OFFSET, 0x00abcdef);
EXPECT_WRITE32(OTP_CTRL_DIRECT_ACCESS_WDATA_1_REG_OFFSET, 0xabcdef00);
EXPECT_WRITE32(OTP_CTRL_DIRECT_ACCESS_CMD_REG_OFFSET,
{{OTP_CTRL_DIRECT_ACCESS_CMD_WR_BIT, true}});
EXPECT_DIF_OK(dif_otp_ctrl_dai_digest(&otp_, kDifOtpCtrlPartitionCreatorSwCfg,
/*digest=*/0xabcdef0000abcdef));
}
TEST_F(DaiDigestTest, DigestHw) {
EXPECT_READ32(
OTP_CTRL_DIRECT_ACCESS_REGWEN_REG_OFFSET,
{{OTP_CTRL_DIRECT_ACCESS_REGWEN_DIRECT_ACCESS_REGWEN_BIT, true}});
EXPECT_WRITE32(OTP_CTRL_DIRECT_ACCESS_ADDRESS_REG_OFFSET,
OTP_CTRL_PARAM_DEVICE_ID_OFFSET);
EXPECT_WRITE32(OTP_CTRL_DIRECT_ACCESS_CMD_REG_OFFSET,
{{OTP_CTRL_DIRECT_ACCESS_CMD_DIGEST_BIT, true}});
EXPECT_DIF_OK(
dif_otp_ctrl_dai_digest(&otp_, kDifOtpCtrlPartitionHwCfg, /*digest=*/0));
}
TEST_F(DaiDigestTest, BadPartition) {
EXPECT_EQ(dif_otp_ctrl_dai_digest(&otp_, kDifOtpCtrlPartitionLifeCycle,
/*digest=*/0),
kDifError);
}
TEST_F(DaiDigestTest, Busy) {
EXPECT_READ32(
OTP_CTRL_DIRECT_ACCESS_REGWEN_REG_OFFSET,
{{OTP_CTRL_DIRECT_ACCESS_REGWEN_DIRECT_ACCESS_REGWEN_BIT, false}});
EXPECT_EQ(
dif_otp_ctrl_dai_digest(&otp_, kDifOtpCtrlPartitionHwCfg, /*digest=*/0),
kDifUnavailable);
}
TEST_F(DaiDigestTest, BadDigest) {
EXPECT_DIF_BADARG(dif_otp_ctrl_dai_digest(&otp_, kDifOtpCtrlPartitionHwCfg,
/*digest=*/0xabcdef0000abcdef));
EXPECT_DIF_BADARG(dif_otp_ctrl_dai_digest(&otp_,
kDifOtpCtrlPartitionCreatorSwCfg,
/*digest=*/0));
}
TEST_F(DaiDigestTest, NullArgs) {
EXPECT_DIF_BADARG(dif_otp_ctrl_dai_digest(nullptr,
kDifOtpCtrlPartitionCreatorSwCfg,
/*digest=*/0xabcdef0000abcdef));
}
class IsDigestComputed : public OtpTest {};
TEST_F(IsDigestComputed, NullArgs) {
bool is_computed;
EXPECT_DIF_BADARG(dif_otp_ctrl_is_digest_computed(
nullptr, kDifOtpCtrlPartitionSecret2, &is_computed));
EXPECT_DIF_BADARG(dif_otp_ctrl_is_digest_computed(
&otp_, kDifOtpCtrlPartitionSecret2, nullptr));
EXPECT_DIF_BADARG(dif_otp_ctrl_is_digest_computed(
nullptr, kDifOtpCtrlPartitionSecret2, nullptr));
}
TEST_F(IsDigestComputed, BadPartition) {
bool is_computed;
EXPECT_DIF_BADARG(dif_otp_ctrl_is_digest_computed(
&otp_, kDifOtpCtrlPartitionLifeCycle, &is_computed));
}
TEST_F(IsDigestComputed, Success) {
bool is_computed;
EXPECT_READ32(OTP_CTRL_SECRET2_DIGEST_1_REG_OFFSET, 0x98abcdef);
EXPECT_READ32(OTP_CTRL_SECRET2_DIGEST_0_REG_OFFSET, 0xabcdef01);
EXPECT_DIF_OK(dif_otp_ctrl_is_digest_computed(
&otp_, kDifOtpCtrlPartitionSecret2, &is_computed));
EXPECT_TRUE(is_computed);
EXPECT_READ32(OTP_CTRL_SECRET2_DIGEST_1_REG_OFFSET, 0);
EXPECT_READ32(OTP_CTRL_SECRET2_DIGEST_0_REG_OFFSET, 0);
EXPECT_DIF_OK(dif_otp_ctrl_is_digest_computed(
&otp_, kDifOtpCtrlPartitionSecret2, &is_computed));
EXPECT_FALSE(is_computed);
}
struct DigestParams {
dif_otp_ctrl_partition_t partition;
ptrdiff_t reg0, reg1;
};
class GetDigest : public OtpTest,
public testing::WithParamInterface<DigestParams> {};
TEST_P(GetDigest, GetDigest) {
if (GetParam().partition == kDifOtpCtrlPartitionLifeCycle) {
uint64_t digest;
EXPECT_DIF_BADARG(
dif_otp_ctrl_get_digest(&otp_, GetParam().partition, &digest));
return;
}
EXPECT_READ32(GetParam().reg1, 0xabcdef99);
EXPECT_READ32(GetParam().reg0, 0x99abcdef);
uint64_t digest;
EXPECT_DIF_OK(dif_otp_ctrl_get_digest(&otp_, GetParam().partition, &digest));
EXPECT_EQ(digest, 0xabcdef9999abcdef);
}
TEST_P(GetDigest, BadDigest) {
if (GetParam().partition == kDifOtpCtrlPartitionLifeCycle) {
return;
}
EXPECT_READ32(GetParam().reg1, 0x0);
EXPECT_READ32(GetParam().reg0, 0x0);
uint64_t digest;
EXPECT_EQ(dif_otp_ctrl_get_digest(&otp_, GetParam().partition, &digest),
kDifError);
}
TEST_P(GetDigest, NullArgs) {
uint64_t digest;
EXPECT_DIF_BADARG(
dif_otp_ctrl_get_digest(nullptr, GetParam().partition, &digest));
EXPECT_DIF_BADARG(
dif_otp_ctrl_get_digest(&otp_, GetParam().partition, nullptr));
}
INSTANTIATE_TEST_SUITE_P(AllDigests, GetDigest,
testing::Values(
DigestParams{
kDifOtpCtrlPartitionCreatorSwCfg,
OTP_CTRL_CREATOR_SW_CFG_DIGEST_0_REG_OFFSET,
OTP_CTRL_CREATOR_SW_CFG_DIGEST_1_REG_OFFSET,
},
DigestParams{
kDifOtpCtrlPartitionOwnerSwCfg,
OTP_CTRL_OWNER_SW_CFG_DIGEST_0_REG_OFFSET,
OTP_CTRL_OWNER_SW_CFG_DIGEST_1_REG_OFFSET,
},
DigestParams{
kDifOtpCtrlPartitionHwCfg,
OTP_CTRL_HW_CFG_DIGEST_0_REG_OFFSET,
OTP_CTRL_HW_CFG_DIGEST_1_REG_OFFSET,
},
DigestParams{
kDifOtpCtrlPartitionSecret0,
OTP_CTRL_SECRET0_DIGEST_0_REG_OFFSET,
OTP_CTRL_SECRET0_DIGEST_1_REG_OFFSET,
},
DigestParams{
kDifOtpCtrlPartitionSecret1,
OTP_CTRL_SECRET1_DIGEST_0_REG_OFFSET,
OTP_CTRL_SECRET1_DIGEST_1_REG_OFFSET,
},
DigestParams{
kDifOtpCtrlPartitionSecret2,
OTP_CTRL_SECRET2_DIGEST_0_REG_OFFSET,
OTP_CTRL_SECRET2_DIGEST_1_REG_OFFSET,
},
DigestParams{
kDifOtpCtrlPartitionLifeCycle,
0,
0,
}));
class BlockingIoTest : public OtpTest {
protected:
static constexpr size_t kWords = 4;
};
TEST_F(BlockingIoTest, Read) {
for (size_t i = 0; i < kWords; ++i) {
auto offset =
OTP_CTRL_PARAM_OWNER_SW_CFG_OFFSET + 0x10 + i * sizeof(uint32_t);
EXPECT_READ32(OTP_CTRL_SW_CFG_WINDOW_REG_OFFSET + offset, i + 1);
}
std::vector<uint32_t> buf(kWords);
EXPECT_DIF_OK(dif_otp_ctrl_read_blocking(
&otp_, kDifOtpCtrlPartitionOwnerSwCfg, 0x10, buf.data(), buf.size()));
EXPECT_THAT(buf, ElementsAre(1, 2, 3, 4));
}
TEST_F(BlockingIoTest, BadPartition) {
std::vector<uint32_t> buf(kWords);
EXPECT_EQ(dif_otp_ctrl_read_blocking(&otp_, kDifOtpCtrlPartitionHwCfg, 0x10,
buf.data(), buf.size()),
kDifError);
}
TEST_F(BlockingIoTest, Unaligned) {
std::vector<uint32_t> buf(kWords);
EXPECT_EQ(dif_otp_ctrl_read_blocking(&otp_, kDifOtpCtrlPartitionOwnerSwCfg,
0x11, buf.data(), buf.size()),
kDifUnaligned);
}
TEST_F(BlockingIoTest, OutOfRange) {
std::vector<uint32_t> buf(0x2f0);
EXPECT_EQ(dif_otp_ctrl_read_blocking(&otp_, kDifOtpCtrlPartitionOwnerSwCfg,
0x300, buf.data(), buf.size()),
kDifOutOfRange);
EXPECT_EQ(dif_otp_ctrl_read_blocking(&otp_, kDifOtpCtrlPartitionOwnerSwCfg,
0x10, buf.data(), 0x330),
kDifOutOfRange);
}
TEST_F(BlockingIoTest, NullArgs) {
std::vector<uint32_t> buf(kWords);
EXPECT_DIF_BADARG(dif_otp_ctrl_read_blocking(
nullptr, kDifOtpCtrlPartitionOwnerSwCfg, 0x10, buf.data(), buf.size()));
EXPECT_DIF_BADARG(dif_otp_ctrl_read_blocking(
&otp_, kDifOtpCtrlPartitionOwnerSwCfg, 0x10, nullptr, buf.size()));
}
} // namespace
} // namespace dif_otp_ctrl_unittest