blob: aca02294e7e59806576813fc70eeb89c66997043 [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_otbn.h"
#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_base.h"
#include "sw/device/lib/dif/dif_test_base.h"
#include "otbn_regs.h" // Generated.
namespace dif_otbn_unittest {
namespace {
using mock_mmio::MmioTest;
using mock_mmio::MockDevice;
using testing::Each;
using testing::Eq;
using testing::Test;
class OtbnTest : public Test, public MmioTest {
protected:
void ExpectDeviceReset() {
EXPECT_WRITE32(OTBN_INTR_ENABLE_REG_OFFSET, 0);
EXPECT_WRITE32(OTBN_INTR_STATE_REG_OFFSET,
std::numeric_limits<uint32_t>::max());
}
dif_otbn_t dif_otbn_ = {.base_addr = dev().region()};
};
class ResetTest : public OtbnTest {};
TEST_F(ResetTest, NullArgs) { EXPECT_DIF_BADARG(dif_otbn_reset(nullptr)); }
TEST_F(ResetTest, Default) {
ExpectDeviceReset();
EXPECT_DIF_OK(dif_otbn_reset(&dif_otbn_));
}
class WriteCmdTest : public OtbnTest {};
TEST_F(WriteCmdTest, NullArgs) {
EXPECT_DIF_BADARG(dif_otbn_write_cmd(nullptr, kDifOtbnCmdExecute));
}
TEST_F(WriteCmdTest, Success) {
// Set EXECUTE command.
EXPECT_WRITE32(OTBN_CMD_REG_OFFSET, kDifOtbnCmdExecute);
EXPECT_DIF_OK(dif_otbn_write_cmd(&dif_otbn_, kDifOtbnCmdExecute));
}
class GetStatusTest : public OtbnTest {};
TEST_F(GetStatusTest, NullArgs) {
EXPECT_DIF_BADARG(dif_otbn_get_status(nullptr, nullptr));
EXPECT_DIF_BADARG(dif_otbn_get_status(&dif_otbn_, nullptr));
dif_otbn_status_t status = kDifOtbnStatusBusySecWipeDmem;
EXPECT_DIF_BADARG(dif_otbn_get_status(nullptr, &status));
EXPECT_EQ(status, kDifOtbnStatusBusySecWipeDmem);
}
TEST_F(GetStatusTest, Success) {
EXPECT_READ32(OTBN_STATUS_REG_OFFSET, kDifOtbnStatusBusyExecute);
dif_otbn_status_t status;
EXPECT_DIF_OK(dif_otbn_get_status(&dif_otbn_, &status));
EXPECT_EQ(status, kDifOtbnStatusBusyExecute);
}
class GetErrBitsTest : public OtbnTest {};
TEST_F(GetErrBitsTest, NullArgs) {
EXPECT_DIF_BADARG(dif_otbn_get_err_bits(nullptr, nullptr));
EXPECT_DIF_BADARG(dif_otbn_get_err_bits(&dif_otbn_, nullptr));
dif_otbn_err_bits_t err_bits = kDifOtbnErrBitsBadDataAddr;
EXPECT_DIF_BADARG(dif_otbn_get_err_bits(nullptr, &err_bits));
EXPECT_EQ(err_bits, kDifOtbnErrBitsBadDataAddr);
}
TEST_F(GetErrBitsTest, Success) {
EXPECT_READ32(OTBN_ERR_BITS_REG_OFFSET,
kDifOtbnErrBitsIllegalInsn | kDifOtbnErrBitsRegIntgViolation);
dif_otbn_err_bits_t err_bits;
EXPECT_DIF_OK(dif_otbn_get_err_bits(&dif_otbn_, &err_bits));
EXPECT_EQ(err_bits,
kDifOtbnErrBitsIllegalInsn | kDifOtbnErrBitsRegIntgViolation);
}
class GetInsnCntTest : public OtbnTest {};
TEST_F(GetInsnCntTest, NullArgs) {
EXPECT_DIF_BADARG(dif_otbn_get_insn_cnt(nullptr, nullptr));
EXPECT_DIF_BADARG(dif_otbn_get_insn_cnt(&dif_otbn_, nullptr));
uint32_t insn_cnt = 55;
EXPECT_DIF_BADARG(dif_otbn_get_insn_cnt(nullptr, &insn_cnt));
EXPECT_EQ(insn_cnt, 55);
}
TEST_F(GetInsnCntTest, Success) {
EXPECT_READ32(OTBN_INSN_CNT_REG_OFFSET, 55);
uint32_t insn_cnt;
EXPECT_DIF_OK(dif_otbn_get_insn_cnt(&dif_otbn_, &insn_cnt));
EXPECT_EQ(insn_cnt, 55);
}
class ImemWriteTest : public OtbnTest {};
TEST_F(ImemWriteTest, NullArgs) {
uint32_t test_data[] = {0};
EXPECT_DIF_BADARG(dif_otbn_imem_write(nullptr, 0, nullptr, 4));
EXPECT_DIF_BADARG(dif_otbn_imem_write(nullptr, 0, test_data, 4));
EXPECT_DIF_BADARG(dif_otbn_imem_write(&dif_otbn_, 0, nullptr, 4));
}
TEST_F(ImemWriteTest, BadLenBytes) {
uint32_t test_data[] = {0};
// `len_bytes` must be a multiple of 4 bytes.
EXPECT_DIF_BADARG(dif_otbn_imem_write(&dif_otbn_, 0, test_data, 1));
EXPECT_DIF_BADARG(dif_otbn_imem_write(&dif_otbn_, 0, test_data, 2));
}
TEST_F(ImemWriteTest, BadOffset) {
uint32_t test_data[] = {0};
// `offset` must be 32b-aligned.
EXPECT_DIF_BADARG(dif_otbn_imem_write(&dif_otbn_, 1, test_data, 4));
EXPECT_DIF_BADARG(dif_otbn_imem_write(&dif_otbn_, 2, test_data, 4));
}
TEST_F(ImemWriteTest, BadAddressBeyondMemorySize) {
uint32_t test_data[] = {0};
EXPECT_DIF_BADARG(
dif_otbn_imem_write(&dif_otbn_, OTBN_IMEM_SIZE_BYTES, test_data, 4));
}
TEST_F(ImemWriteTest, BadAddressIntegerOverflow) {
uint32_t test_data[4] = {0};
EXPECT_DIF_BADARG(dif_otbn_imem_write(&dif_otbn_, 0xFFFFFFFC, test_data, 16));
}
TEST_F(ImemWriteTest, SuccessWithoutOffset) {
// Test assumption.
ASSERT_GE(OTBN_IMEM_SIZE_BYTES, 8);
uint32_t test_data[2] = {0x12345678, 0xabcdef01};
EXPECT_WRITE32(OTBN_IMEM_REG_OFFSET, test_data[0]);
EXPECT_WRITE32(OTBN_IMEM_REG_OFFSET + 4, test_data[1]);
EXPECT_DIF_OK(dif_otbn_imem_write(&dif_otbn_, 0, test_data, 8));
}
TEST_F(ImemWriteTest, SuccessWithOffset) {
// Test assumption.
ASSERT_GE(OTBN_IMEM_SIZE_BYTES, 12);
uint32_t test_data[2] = {0x12345678, 0xabcdef01};
EXPECT_WRITE32(OTBN_IMEM_REG_OFFSET + 4, test_data[0]);
EXPECT_WRITE32(OTBN_IMEM_REG_OFFSET + 8, test_data[1]);
EXPECT_DIF_OK(dif_otbn_imem_write(&dif_otbn_, 4, test_data, 8));
}
class ImemReadTest : public OtbnTest {};
TEST_F(ImemReadTest, NullArgs) {
uint32_t test_data[2] = {0x12345678, 0xabcdef01};
EXPECT_DIF_BADARG(dif_otbn_imem_read(nullptr, 0, nullptr, sizeof(test_data)));
EXPECT_DIF_BADARG(
dif_otbn_imem_read(nullptr, 0, test_data, sizeof(test_data)));
EXPECT_DIF_BADARG(
dif_otbn_imem_read(&dif_otbn_, 0, nullptr, sizeof(test_data)));
// No side effects are expected.
EXPECT_EQ(test_data[0], 0x12345678);
EXPECT_EQ(test_data[1], 0xabcdef01);
}
TEST_F(ImemReadTest, BadLenBytes) {
uint32_t test_data[2] = {0};
// `len_bytes` must be a multiple of 4 bytes.
EXPECT_DIF_BADARG(dif_otbn_imem_read(&dif_otbn_, 0, test_data, 1));
EXPECT_DIF_BADARG(dif_otbn_imem_read(&dif_otbn_, 0, test_data, 2));
}
TEST_F(ImemReadTest, BadOffset) {
uint32_t test_data[2] = {0};
// `offset` must be 32b-aligned.
EXPECT_DIF_BADARG(
dif_otbn_imem_read(&dif_otbn_, 1, test_data, sizeof(test_data)));
EXPECT_DIF_BADARG(
dif_otbn_imem_read(&dif_otbn_, 2, test_data, sizeof(test_data)));
}
TEST_F(ImemReadTest, SuccessWithoutOffset) {
// Assumption in the test.
ASSERT_GE(OTBN_IMEM_SIZE_BYTES, 8);
uint32_t test_data[2] = {0};
EXPECT_READ32(OTBN_IMEM_REG_OFFSET, 0x12345678);
EXPECT_READ32(OTBN_IMEM_REG_OFFSET + 4, 0xabcdef01);
EXPECT_DIF_OK(dif_otbn_imem_read(&dif_otbn_, 0, test_data, 8));
EXPECT_EQ(test_data[0], 0x12345678);
EXPECT_EQ(test_data[1], 0xabcdef01);
}
TEST_F(ImemReadTest, SuccessWithOffset) {
// Assumption in the test.
ASSERT_GE(OTBN_IMEM_SIZE_BYTES, 12);
uint32_t test_data[2] = {0};
EXPECT_READ32(OTBN_IMEM_REG_OFFSET + 4, 0x12345678);
EXPECT_READ32(OTBN_IMEM_REG_OFFSET + 8, 0xabcdef01);
EXPECT_DIF_OK(dif_otbn_imem_read(&dif_otbn_, 4, test_data, 8));
EXPECT_EQ(test_data[0], 0x12345678);
EXPECT_EQ(test_data[1], 0xabcdef01);
}
class DmemWriteTest : public OtbnTest {};
TEST_F(DmemWriteTest, NullArgs) {
uint32_t test_data[1] = {0};
EXPECT_DIF_BADARG(dif_otbn_dmem_write(nullptr, 0, nullptr, 4));
EXPECT_DIF_BADARG(dif_otbn_dmem_write(nullptr, 0, test_data, 4));
EXPECT_DIF_BADARG(dif_otbn_dmem_write(&dif_otbn_, 0, nullptr, 4));
}
TEST_F(DmemWriteTest, BadLenBytes) {
uint32_t test_data[1] = {0};
// `len_bytes` must be a multiple of 4 bytes.
EXPECT_DIF_BADARG(dif_otbn_dmem_write(&dif_otbn_, 0, test_data, 1));
EXPECT_DIF_BADARG(dif_otbn_dmem_write(&dif_otbn_, 0, test_data, 2));
}
TEST_F(DmemWriteTest, BadOffset) {
uint32_t test_data[1] = {0};
// `offset` must be 32b-aligned.
EXPECT_DIF_BADARG(dif_otbn_dmem_write(&dif_otbn_, 1, test_data, 4));
EXPECT_DIF_BADARG(dif_otbn_dmem_write(&dif_otbn_, 2, test_data, 4));
}
TEST_F(DmemWriteTest, SuccessWithoutOffset) {
// Test assumption.
ASSERT_GE(OTBN_DMEM_SIZE_BYTES, 8);
uint32_t test_data[2] = {0x12345678, 0xabcdef01};
EXPECT_WRITE32(OTBN_DMEM_REG_OFFSET, test_data[0]);
EXPECT_WRITE32(OTBN_DMEM_REG_OFFSET + 4, test_data[1]);
EXPECT_DIF_OK(dif_otbn_dmem_write(&dif_otbn_, 0, test_data, 8));
}
TEST_F(DmemWriteTest, SuccessWithOffset) {
// Test assumption.
ASSERT_GE(OTBN_DMEM_SIZE_BYTES, 12);
uint32_t test_data[2] = {0x12345678, 0xabcdef01};
EXPECT_WRITE32(OTBN_DMEM_REG_OFFSET + 4, test_data[0]);
EXPECT_WRITE32(OTBN_DMEM_REG_OFFSET + 8, test_data[1]);
EXPECT_DIF_OK(dif_otbn_dmem_write(&dif_otbn_, 4, test_data, 8));
}
class DmemReadTest : public OtbnTest {};
TEST_F(DmemReadTest, NullArgs) {
uint32_t test_data[2] = {0x12345678, 0xabcdef01};
EXPECT_DIF_BADARG(dif_otbn_dmem_read(nullptr, 0, nullptr, sizeof(test_data)));
EXPECT_DIF_BADARG(
dif_otbn_dmem_read(nullptr, 0, test_data, sizeof(test_data)));
EXPECT_DIF_BADARG(
dif_otbn_dmem_read(&dif_otbn_, 0, nullptr, sizeof(test_data)));
// No side effects are expected.
EXPECT_EQ(test_data[0], 0x12345678);
EXPECT_EQ(test_data[1], 0xabcdef01);
}
TEST_F(DmemReadTest, BadLenBytes) {
uint32_t test_data[2] = {0};
// `len_bytes` must be a multiple of 4 bytes.
EXPECT_DIF_BADARG(dif_otbn_dmem_read(&dif_otbn_, 0, test_data, 1));
EXPECT_DIF_BADARG(dif_otbn_dmem_read(&dif_otbn_, 0, test_data, 2));
}
TEST_F(DmemReadTest, BadOffset) {
uint32_t test_data[2] = {0};
// `offset` must be 32b-aligned.
EXPECT_DIF_BADARG(
dif_otbn_dmem_read(&dif_otbn_, 1, test_data, sizeof(test_data)));
EXPECT_DIF_BADARG(
dif_otbn_dmem_read(&dif_otbn_, 2, test_data, sizeof(test_data)));
}
TEST_F(DmemReadTest, SuccessWithoutOffset) {
// Assumption in the test.
ASSERT_GE(OTBN_DMEM_SIZE_BYTES, 8);
uint32_t test_data[2] = {0};
EXPECT_READ32(OTBN_DMEM_REG_OFFSET, 0x12345678);
EXPECT_READ32(OTBN_DMEM_REG_OFFSET + 4, 0xabcdef01);
EXPECT_DIF_OK(dif_otbn_dmem_read(&dif_otbn_, 0, test_data, 8));
EXPECT_EQ(test_data[0], 0x12345678);
EXPECT_EQ(test_data[1], 0xabcdef01);
}
TEST_F(DmemReadTest, SuccessWithOffset) {
// Assumption in the test.
ASSERT_GE(OTBN_DMEM_SIZE_BYTES, 12);
uint32_t test_data[2] = {0};
EXPECT_READ32(OTBN_DMEM_REG_OFFSET + 4, 0x12345678);
EXPECT_READ32(OTBN_DMEM_REG_OFFSET + 8, 0xabcdef01);
EXPECT_DIF_OK(dif_otbn_dmem_read(&dif_otbn_, 4, test_data, 8));
EXPECT_EQ(test_data[0], 0x12345678);
EXPECT_EQ(test_data[1], 0xabcdef01);
}
class ControlSoftwareErrorsFatalTest : public OtbnTest {};
TEST_F(ControlSoftwareErrorsFatalTest, NullArgs) {
EXPECT_DIF_BADARG(dif_otbn_set_ctrl_software_errs_fatal(nullptr, false));
}
TEST_F(ControlSoftwareErrorsFatalTest, Success) {
EXPECT_WRITE32(OTBN_CTRL_REG_OFFSET, 0x1);
EXPECT_READ32(OTBN_CTRL_REG_OFFSET, 0x1);
EXPECT_DIF_OK(dif_otbn_set_ctrl_software_errs_fatal(&dif_otbn_, true));
}
TEST_F(ControlSoftwareErrorsFatalTest, Failure) {
EXPECT_WRITE32(OTBN_CTRL_REG_OFFSET, 0x0);
EXPECT_READ32(OTBN_CTRL_REG_OFFSET, 0x1);
EXPECT_EQ(dif_otbn_set_ctrl_software_errs_fatal(&dif_otbn_, false),
kDifUnavailable);
}
} // namespace
} // namespace dif_otbn_unittest