[dif/edn] Add unit tests
Signed-off-by: Miguel Young de la Sota <mcyoung@google.com>
diff --git a/sw/device/lib/dif/BUILD b/sw/device/lib/dif/BUILD
index acf3e79..038d957 100644
--- a/sw/device/lib/dif/BUILD
+++ b/sw/device/lib/dif/BUILD
@@ -273,6 +273,7 @@
name = "edn_unittest",
srcs = [
"autogen/dif_edn_autogen_unittest.cc",
+ "dif_edn_unittest.cc",
],
deps = [
":edn",
diff --git a/sw/device/lib/dif/dif_edn.c b/sw/device/lib/dif/dif_edn.c
index 9222f7f..f61b243 100644
--- a/sw/device/lib/dif/dif_edn.c
+++ b/sw/device/lib/dif/dif_edn.c
@@ -161,6 +161,7 @@
break;
case kDifEdnFifoGenerateCmd:
fifo_bit = EDN_ERR_CODE_SFIFO_GENCMD_ERR_BIT;
+ break;
default:
return kDifBadArg;
}
diff --git a/sw/device/lib/dif/dif_edn_unittest.cc b/sw/device/lib/dif/dif_edn_unittest.cc
new file mode 100644
index 0000000..8f4b148
--- /dev/null
+++ b/sw/device/lib/dif/dif_edn_unittest.cc
@@ -0,0 +1,373 @@
+// 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_edn.h"
+
+#include <array>
+#include <vector>
+
+#include "gtest/gtest.h"
+#include "sw/device/lib/base/mmio.h"
+#include "sw/device/lib/base/testing/mock_mmio.h"
+#include "sw/device/lib/dif/dif_test_base.h"
+
+#include "edn_regs.h" // Generated
+
+namespace dif_edn_unittest {
+namespace {
+
+using ::testing::ElementsAreArray;
+
+class DifEdnTest : public testing::Test, public mock_mmio::MmioTest {
+ protected:
+ const dif_edn_t edn_ = {.base_addr = dev().region()};
+};
+
+class ConfigTest : public DifEdnTest {};
+
+TEST_F(ConfigTest, BadArgs) { EXPECT_DIF_BADARG(dif_edn_configure(nullptr)); }
+
+TEST_F(ConfigTest, ConfigOk) {
+ EXPECT_READ32(EDN_REGWEN_REG_OFFSET, 1);
+ EXPECT_MASK32(EDN_CTRL_REG_OFFSET,
+ {
+ {EDN_CTRL_EDN_ENABLE_OFFSET, 0xf, kMultiBitBool4True},
+ });
+ EXPECT_DIF_OK(dif_edn_configure(&edn_));
+}
+
+TEST_F(ConfigTest, Locked) {
+ EXPECT_READ32(EDN_REGWEN_REG_OFFSET, 0);
+ EXPECT_EQ(dif_edn_configure(&edn_), kDifLocked);
+}
+
+class LockTest : public DifEdnTest {};
+
+TEST_F(LockTest, BadArgs) {
+ bool flag;
+ EXPECT_DIF_BADARG(dif_edn_lock(nullptr));
+ EXPECT_DIF_BADARG(dif_edn_is_locked(nullptr, &flag));
+ EXPECT_DIF_BADARG(dif_edn_is_locked(&edn_, nullptr));
+}
+
+TEST_F(LockTest, Lock) {
+ EXPECT_WRITE32(EDN_REGWEN_REG_OFFSET, 0);
+ EXPECT_DIF_OK(dif_edn_lock(&edn_));
+}
+
+TEST_F(LockTest, IsLocked) {
+ bool flag;
+
+ EXPECT_READ32(EDN_REGWEN_REG_OFFSET, 1);
+ EXPECT_DIF_OK(dif_edn_is_locked(&edn_, &flag));
+ EXPECT_FALSE(flag);
+
+ EXPECT_READ32(EDN_REGWEN_REG_OFFSET, 0);
+ EXPECT_DIF_OK(dif_edn_is_locked(&edn_, &flag));
+ EXPECT_TRUE(flag);
+}
+
+class SetModeTest : public DifEdnTest {};
+
+TEST_F(SetModeTest, BadArgs) {
+ EXPECT_DIF_BADARG(dif_edn_set_boot_mode(nullptr));
+ EXPECT_DIF_BADARG(dif_edn_set_auto_mode(nullptr, {}));
+}
+
+TEST_F(SetModeTest, Boot) {
+ EXPECT_READ32(EDN_REGWEN_REG_OFFSET, 1);
+ EXPECT_MASK32(EDN_CTRL_REG_OFFSET,
+ {
+ {EDN_CTRL_BOOT_REQ_MODE_OFFSET, 0xf, kMultiBitBool4True},
+ });
+ EXPECT_DIF_OK(dif_edn_set_boot_mode(&edn_));
+}
+
+TEST_F(SetModeTest, Auto) {
+ EXPECT_READ32(EDN_REGWEN_REG_OFFSET, 1);
+
+ EXPECT_READ32(EDN_CTRL_REG_OFFSET, EDN_CTRL_REG_RESVAL);
+ EXPECT_WRITE32(EDN_CTRL_REG_OFFSET,
+ {
+ {EDN_CTRL_EDN_ENABLE_OFFSET, kMultiBitBool4False},
+ {EDN_CTRL_BOOT_REQ_MODE_OFFSET, kMultiBitBool4False},
+ {EDN_CTRL_AUTO_REQ_MODE_OFFSET, kMultiBitBool4False},
+ {EDN_CTRL_CMD_FIFO_RST_OFFSET, kMultiBitBool4True},
+ });
+
+ dif_edn_auto_params_t params = {
+ .reseed_material =
+ {
+ .len = 5,
+ .data = {1, 2, 3, 4, 5},
+ },
+ .generate_material =
+ {
+ .len = 7,
+ .data = {6, 7, 8, 9, 10, 11, 12},
+ },
+ .reseed_interval = 42,
+ };
+
+ for (size_t i = 0; i < params.reseed_material.len; ++i) {
+ EXPECT_WRITE32(EDN_RESEED_CMD_REG_OFFSET, params.reseed_material.data[i]);
+ }
+ for (size_t i = 0; i < params.generate_material.len; ++i) {
+ EXPECT_WRITE32(EDN_GENERATE_CMD_REG_OFFSET,
+ params.generate_material.data[i]);
+ }
+ EXPECT_WRITE32(EDN_MAX_NUM_REQS_BETWEEN_RESEEDS_REG_OFFSET,
+ params.reseed_interval);
+
+ EXPECT_WRITE32(EDN_CTRL_REG_OFFSET,
+ {
+ {EDN_CTRL_EDN_ENABLE_OFFSET, kMultiBitBool4False},
+ {EDN_CTRL_BOOT_REQ_MODE_OFFSET, kMultiBitBool4False},
+ {EDN_CTRL_AUTO_REQ_MODE_OFFSET, kMultiBitBool4True},
+ {EDN_CTRL_CMD_FIFO_RST_OFFSET, kMultiBitBool4True},
+ });
+
+ EXPECT_DIF_OK(dif_edn_set_auto_mode(&edn_, params));
+}
+
+TEST_F(SetModeTest, Locked) {
+ EXPECT_READ32(EDN_REGWEN_REG_OFFSET, 0);
+ EXPECT_READ32(EDN_REGWEN_REG_OFFSET, 0);
+ EXPECT_EQ(dif_edn_set_boot_mode(&edn_), kDifLocked);
+ EXPECT_EQ(dif_edn_set_auto_mode(&edn_, {}), kDifLocked);
+}
+
+class GetStatusTest : public DifEdnTest {};
+
+TEST_F(GetStatusTest, BadArgs) {
+ bool flag;
+ EXPECT_DIF_BADARG(dif_edn_get_status(nullptr, kDifEdnStatusReady, &flag));
+ EXPECT_DIF_BADARG(
+ dif_edn_get_status(&edn_, static_cast<dif_edn_status_t>(-1), &flag));
+ EXPECT_DIF_BADARG(dif_edn_get_status(&edn_, kDifEdnStatusReady, nullptr));
+}
+
+TEST_F(GetStatusTest, Ok) {
+ bool flag;
+
+ EXPECT_READ32(EDN_SW_CMD_STS_REG_OFFSET,
+ {
+ {EDN_SW_CMD_STS_CMD_RDY_BIT, true},
+ {EDN_SW_CMD_STS_CMD_STS_BIT, false},
+ });
+ EXPECT_DIF_OK(dif_edn_get_status(&edn_, kDifEdnStatusReady, &flag));
+ EXPECT_TRUE(flag);
+
+ EXPECT_READ32(EDN_SW_CMD_STS_REG_OFFSET,
+ {
+ {EDN_SW_CMD_STS_CMD_RDY_BIT, true},
+ {EDN_SW_CMD_STS_CMD_STS_BIT, false},
+ });
+ EXPECT_DIF_OK(dif_edn_get_status(&edn_, kDifEdnStatusCsrngAck, &flag));
+ EXPECT_FALSE(flag);
+}
+
+class ErrorTest : public DifEdnTest {};
+
+TEST_F(ErrorTest, BadArgs) {
+ uint32_t set;
+ EXPECT_DIF_BADARG(dif_edn_get_errors(nullptr, &set, &set));
+ EXPECT_DIF_BADARG(dif_edn_get_errors(&edn_, nullptr, &set));
+ EXPECT_DIF_BADARG(dif_edn_get_errors(&edn_, &set, nullptr));
+ EXPECT_DIF_BADARG(dif_edn_get_cmd_unhealthy_fifo_force(
+ &edn_, static_cast<dif_edn_fifo_t>(-1)));
+ EXPECT_DIF_BADARG(
+ dif_edn_get_cmd_unhealthy_fifo_force(nullptr, kDifEdnFifoReseedCmd));
+ EXPECT_DIF_BADARG(
+ dif_edn_get_cmd_error_force(&edn_, static_cast<dif_edn_error_t>(-1)));
+ EXPECT_DIF_BADARG(dif_edn_get_cmd_error_force(nullptr, kDifEdnErrorMainSm));
+}
+
+TEST_F(ErrorTest, Ok) {
+ EXPECT_READ32(EDN_ERR_CODE_REG_OFFSET,
+ {
+ {EDN_ERR_CODE_SFIFO_RESCMD_ERR_BIT, true},
+ {EDN_ERR_CODE_EDN_MAIN_SM_ERR_BIT, true},
+ {EDN_ERR_CODE_FIFO_STATE_ERR_BIT, true},
+ });
+
+ uint32_t fifos, errors;
+ EXPECT_DIF_OK(dif_edn_get_errors(&edn_, &fifos, &errors));
+ EXPECT_EQ(fifos, 1 << kDifEdnFifoReseedCmd);
+ EXPECT_EQ(errors,
+ 1 << kDifEdnErrorMainSm | 1 << kDifEdnErrorFifoFullAndEmpty);
+}
+
+TEST_F(ErrorTest, ForceFifo) {
+ EXPECT_READ32(EDN_REGWEN_REG_OFFSET, 1);
+ EXPECT_WRITE32(EDN_ERR_CODE_TEST_REG_OFFSET,
+ EDN_ERR_CODE_SFIFO_RESCMD_ERR_BIT);
+ EXPECT_DIF_OK(
+ dif_edn_get_cmd_unhealthy_fifo_force(&edn_, kDifEdnFifoReseedCmd));
+}
+
+TEST_F(ErrorTest, ForceError) {
+ EXPECT_READ32(EDN_REGWEN_REG_OFFSET, 1);
+ EXPECT_WRITE32(EDN_ERR_CODE_TEST_REG_OFFSET,
+ EDN_ERR_CODE_EDN_MAIN_SM_ERR_BIT);
+ EXPECT_DIF_OK(dif_edn_get_cmd_error_force(&edn_, kDifEdnErrorMainSm));
+}
+
+TEST_F(ErrorTest, Locked) {
+ EXPECT_READ32(EDN_REGWEN_REG_OFFSET, 0);
+ EXPECT_READ32(EDN_REGWEN_REG_OFFSET, 0);
+ EXPECT_EQ(dif_edn_get_cmd_unhealthy_fifo_force(&edn_, kDifEdnFifoReseedCmd),
+ kDifLocked);
+ EXPECT_EQ(dif_edn_get_cmd_error_force(&edn_, kDifEdnErrorMainSm), kDifLocked);
+}
+
+class MiscStatusTest : public DifEdnTest {};
+
+TEST_F(MiscStatusTest, BadArgs) {
+ uint32_t out;
+ EXPECT_DIF_BADARG(dif_edn_get_main_state_machine(nullptr, &out));
+ EXPECT_DIF_BADARG(dif_edn_get_main_state_machine(&edn_, nullptr));
+}
+
+TEST_F(MiscStatusTest, GetMainSm) {
+ EXPECT_READ32(EDN_MAIN_SM_STATE_REG_OFFSET, 42);
+
+ uint32_t out;
+ EXPECT_DIF_OK(dif_edn_get_main_state_machine(&edn_, &out));
+ EXPECT_EQ(out, 42);
+}
+
+/**
+ * DRBG commands are tested using this test group as the underlying
+ * command interface is shared across API functions.
+ */
+class CommandTest : public DifEdnTest {
+ protected:
+ dif_edn_seed_material_t seed_material_{};
+};
+
+TEST_F(CommandTest, InstantiateOk) {
+ EXPECT_WRITE32(EDN_SW_CMD_REQ_REG_OFFSET, 0x00000101);
+ EXPECT_DIF_OK(dif_edn_instantiate(&edn_, kDifEdnEntropySrcToggleDisable,
+ &seed_material_));
+
+ EXPECT_WRITE32(EDN_SW_CMD_REQ_REG_OFFSET, 0x00000001);
+ EXPECT_DIF_OK(dif_edn_instantiate(&edn_, kDifEdnEntropySrcToggleEnable,
+ &seed_material_));
+
+ seed_material_.data[0] = 0x5a5a5a5a;
+ seed_material_.len = 1;
+ EXPECT_WRITE32(EDN_SW_CMD_REQ_REG_OFFSET, 0x00000011);
+ EXPECT_WRITE32(EDN_SW_CMD_REQ_REG_OFFSET, 0x5a5a5a5a);
+ EXPECT_DIF_OK(dif_edn_instantiate(&edn_, kDifEdnEntropySrcToggleEnable,
+ &seed_material_));
+}
+
+TEST_F(CommandTest, InstantiateBadArgs) {
+ EXPECT_DIF_BADARG(dif_edn_instantiate(nullptr, kDifEdnEntropySrcToggleDisable,
+ &seed_material_));
+
+ // Failed overflow check.
+ seed_material_.len = 16;
+ EXPECT_DIF_BADARG(dif_edn_instantiate(&edn_, kDifEdnEntropySrcToggleDisable,
+ &seed_material_));
+}
+
+TEST_F(CommandTest, ReseedOk) {
+ EXPECT_WRITE32(EDN_SW_CMD_REQ_REG_OFFSET, 0x00000002);
+ EXPECT_DIF_OK(dif_edn_reseed(&edn_, &seed_material_));
+
+ seed_material_.data[0] = 0x5a5a5a5a;
+ seed_material_.len = 1;
+ EXPECT_WRITE32(EDN_SW_CMD_REQ_REG_OFFSET, 0x00000012);
+ EXPECT_WRITE32(EDN_SW_CMD_REQ_REG_OFFSET, 0x5a5a5a5a);
+ EXPECT_DIF_OK(dif_edn_reseed(&edn_, &seed_material_));
+}
+
+TEST_F(CommandTest, ReseedBadArgs) {
+ EXPECT_DIF_BADARG(dif_edn_reseed(nullptr, &seed_material_));
+
+ // Failed overflow check.
+ seed_material_.len = 16;
+ EXPECT_DIF_BADARG(dif_edn_reseed(&edn_, &seed_material_));
+}
+
+TEST_F(CommandTest, UpdateOk) {
+ EXPECT_WRITE32(EDN_SW_CMD_REQ_REG_OFFSET, 0x00000004);
+ EXPECT_DIF_OK(dif_edn_update(&edn_, &seed_material_));
+
+ seed_material_.data[0] = 0x5a5a5a5a;
+ seed_material_.len = 1;
+ EXPECT_WRITE32(EDN_SW_CMD_REQ_REG_OFFSET, 0x00000014);
+ EXPECT_WRITE32(EDN_SW_CMD_REQ_REG_OFFSET, 0x5a5a5a5a);
+ EXPECT_DIF_OK(dif_edn_update(&edn_, &seed_material_));
+}
+
+TEST_F(CommandTest, UpdateBadArgs) {
+ EXPECT_DIF_BADARG(dif_edn_update(nullptr, &seed_material_));
+}
+
+TEST_F(CommandTest, GenerateOk) {
+ // 512bits = 16 x 32bit = 4 x 128bit blocks
+ EXPECT_WRITE32(EDN_SW_CMD_REQ_REG_OFFSET, 0x00004003);
+ EXPECT_DIF_OK(dif_edn_generate_start(&edn_, /*len=*/16));
+
+ // 576bits = 18 x 32bit = 5 x 128bit blocks (rounded up)
+ EXPECT_WRITE32(EDN_SW_CMD_REQ_REG_OFFSET, 0x00005003);
+ EXPECT_DIF_OK(dif_edn_generate_start(&edn_, /*len=*/18));
+}
+
+TEST_F(CommandTest, GenerateBadArgs) {
+ EXPECT_DIF_BADARG(dif_edn_generate_start(nullptr, /*len=*/1));
+ EXPECT_DIF_BADARG(dif_edn_generate_start(&edn_, /*len=*/0));
+}
+
+TEST_F(CommandTest, UninstantiateOk) {
+ EXPECT_WRITE32(EDN_SW_CMD_REQ_REG_OFFSET, 0x00000005);
+ EXPECT_DIF_OK(dif_edn_uninstantiate(&edn_));
+}
+
+class StopTest : public DifEdnTest {};
+
+TEST_F(StopTest, BadArgs) { EXPECT_DIF_BADARG(dif_edn_stop(nullptr)); }
+
+TEST_F(StopTest, Stop) {
+ EXPECT_READ32(EDN_REGWEN_REG_OFFSET, 1);
+ EXPECT_WRITE32(EDN_CTRL_REG_OFFSET, EDN_CTRL_REG_RESVAL);
+ EXPECT_DIF_OK(dif_edn_stop(&edn_));
+}
+
+TEST_F(StopTest, Locked) {
+ EXPECT_READ32(EDN_REGWEN_REG_OFFSET, 0);
+ EXPECT_EQ(dif_edn_stop(&edn_), kDifLocked);
+}
+
+class AlertTest : public DifEdnTest {};
+
+TEST_F(AlertTest, BadArgs) {
+ uint32_t out;
+ EXPECT_DIF_BADARG(dif_edn_get_recoverable_alerts(nullptr, &out));
+ EXPECT_DIF_BADARG(dif_edn_get_recoverable_alerts(&edn_, nullptr));
+ EXPECT_DIF_BADARG(dif_edn_clear_recoverable_alerts(nullptr));
+}
+
+TEST_F(AlertTest, Get) {
+ uint32_t out;
+ EXPECT_READ32(EDN_RECOV_ALERT_STS_REG_OFFSET,
+ {
+ {EDN_RECOV_ALERT_STS_BOOT_REQ_MODE_FIELD_ALERT_BIT, true},
+ {EDN_RECOV_ALERT_STS_EDN_BUS_CMP_ALERT_BIT, true},
+ });
+ EXPECT_DIF_OK(dif_edn_get_recoverable_alerts(&edn_, &out));
+ EXPECT_EQ(out, 1 << kDifEdnRecoverableAlertBadBootReqMode |
+ 1 << kDifEdnRecoverableAlertRepeatedGenBits);
+}
+
+TEST_F(AlertTest, Clear) {
+ EXPECT_WRITE32(EDN_RECOV_ALERT_STS_REG_OFFSET, 0);
+ EXPECT_DIF_OK(dif_edn_clear_recoverable_alerts(&edn_));
+}
+
+} // namespace
+} // namespace dif_edn_unittest
diff --git a/sw/device/lib/dif/meson.build b/sw/device/lib/dif/meson.build
index 851d9d9..e821045 100644
--- a/sw/device/lib/dif/meson.build
+++ b/sw/device/lib/dif/meson.build
@@ -93,6 +93,7 @@
sources: [
hw_ip_csrng_reg_h,
'dif_csrng.c',
+ 'dif_csrng_shared.c',
],
dependencies: [
sw_lib_mmio,
@@ -101,26 +102,6 @@
)
)
-test('dif_csrng_unittest', executable(
- 'dif_csrng_unittest',
- sources: [
- 'dif_csrng_unittest.cc',
- 'autogen/dif_csrng_autogen_unittest.cc',
- meson.project_source_root() / 'sw/device/lib/dif/dif_csrng.c',
- meson.project_source_root() / 'sw/device/lib/dif/autogen/dif_csrng_autogen.c',
- hw_ip_csrng_reg_h,
- ],
- dependencies: [
- sw_vendor_gtest,
- sw_lib_base_testing_mock_mmio,
- ],
- native: true,
- c_args: ['-DMOCK_MMIO'],
- cpp_args: ['-DMOCK_MMIO'],
- ),
- suite: 'dif',
-)
-
# EDN DIF Library (dif_csrng)
sw_lib_dif_edn = declare_dependency(
link_with: static_library(
@@ -136,25 +117,6 @@
)
)
-test('dif_edn_unittest', executable(
- 'dif_edn_unittest',
- sources: [
- 'autogen/dif_edn_autogen_unittest.cc',
- meson.project_source_root() / 'sw/device/lib/dif/dif_edn.c',
- meson.project_source_root() / 'sw/device/lib/dif/autogen/dif_edn_autogen.c',
- hw_ip_edn_reg_h,
- ],
- dependencies: [
- sw_vendor_gtest,
- sw_lib_base_testing_mock_mmio,
- ],
- native: true,
- c_args: ['-DMOCK_MMIO'],
- cpp_args: ['-DMOCK_MMIO'],
- ),
- suite: 'dif',
-)
-
# UART DIF library (dif_uart)
sw_lib_dif_uart = declare_dependency(
link_with: static_library(