[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(