| // 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_alert_handler.h" |
| |
| #include <cstring> |
| #include <limits> |
| #include <ostream> |
| |
| #include "gtest/gtest.h" |
| #include "sw/device/lib/base/mmio.h" |
| #include "sw/device/lib/base/testing/mock_mmio.h" |
| |
| #include "alert_handler_regs.h" // Generated. |
| |
| namespace dif_alert_handler_unittest { |
| namespace { |
| using ::mock_mmio::LeInt; |
| using ::mock_mmio::MmioTest; |
| using ::mock_mmio::MockDevice; |
| using ::testing::_; |
| using ::testing::Return; |
| |
| constexpr uint32_t kAlerts = ALERT_HANDLER_PARAM_N_ALERTS; |
| constexpr uint32_t kAllZeros = 0; |
| |
| class AlertHandlerTest : public testing::Test, public MmioTest { |
| protected: |
| dif_alert_handler_t alert_handler_ = {.base_addr = dev().region()}; |
| }; |
| |
| class InitTest : public AlertHandlerTest, |
| public testing::WithParamInterface<uint32_t> {}; |
| |
| TEST_F(InitTest, Success) { |
| dif_alert_handler_t alert_handler; |
| |
| EXPECT_EQ(dif_alert_handler_init(dev().region(), &alert_handler), kDifOk); |
| } |
| |
| TEST_F(InitTest, NullArgs) { |
| EXPECT_EQ(dif_alert_handler_init(dev().region(), nullptr), kDifBadArg); |
| } |
| |
| class ConfigTest : public AlertHandlerTest { |
| // We provide our own dev_ member variable in this fixture, in order to |
| // support IgnoreMmioCalls(). |
| // |
| // NOTE: This must come before alert_handler_! |
| private: |
| std::unique_ptr<MockDevice> dev_ = |
| std::make_unique<testing::StrictMock<MockDevice>>(); |
| |
| protected: |
| ConfigTest() { alert_handler_.base_addr = dev().region(); } |
| // Non-virtual-override dev(), so that EXPECT_*() functions look this one |
| // up instead of AlertHandlerTest::dev(). |
| MockDevice &dev() { return *dev_; } |
| |
| // Disables expectations on MMIO operations. This is useful for configuration |
| // tests that partially configure the device but fail due to a configuration |
| // error, returning kDifError. |
| void IgnoreMmioCalls() { |
| dev_ = std::make_unique<testing::NiceMock<MockDevice>>(); |
| alert_handler_.base_addr = dev().region(); |
| |
| // Make sure that the peripheral looks unlocked. |
| ON_CALL(*dev_, Read32(_)).WillByDefault(Return(kAllZeros)); |
| } |
| }; |
| |
| TEST_F(ConfigTest, Locked) { |
| dif_alert_handler_config_t config = { |
| .ping_timeout = 0, |
| }; |
| |
| EXPECT_READ32( |
| ALERT_HANDLER_PING_TIMER_EN_SHADOWED_REG_OFFSET, |
| {{ALERT_HANDLER_PING_TIMER_EN_SHADOWED_PING_TIMER_EN_SHADOWED_BIT, |
| true}}); |
| |
| EXPECT_EQ(dif_alert_handler_configure(&alert_handler_, config), kDifLocked); |
| } |
| |
| TEST_F(ConfigTest, NoClassInit) { |
| dif_alert_handler_config_t config = { |
| .ping_timeout = 50, |
| }; |
| |
| EXPECT_READ32( |
| ALERT_HANDLER_PING_TIMER_EN_SHADOWED_REG_OFFSET, |
| {{ALERT_HANDLER_PING_TIMER_EN_SHADOWED_PING_TIMER_EN_SHADOWED_BIT, |
| false}}); |
| |
| EXPECT_WRITE32_SHADOWED( |
| ALERT_HANDLER_PING_TIMEOUT_CYC_SHADOWED_REG_OFFSET, |
| {{ALERT_HANDLER_PING_TIMEOUT_CYC_SHADOWED_PING_TIMEOUT_CYC_SHADOWED_OFFSET, |
| 50}}); |
| |
| EXPECT_EQ(dif_alert_handler_configure(&alert_handler_, config), kDifOk); |
| } |
| |
| TEST_F(ConfigTest, TimeoutTooBig) { |
| dif_alert_handler_config_t config = { |
| .ping_timeout = |
| ALERT_HANDLER_PING_TIMEOUT_CYC_SHADOWED_PING_TIMEOUT_CYC_SHADOWED_MASK + |
| 1, |
| }; |
| |
| EXPECT_EQ(dif_alert_handler_configure(&alert_handler_, config), kDifBadArg); |
| } |
| |
| TEST_F(ConfigTest, BadClassPtr) { |
| dif_alert_handler_config_t config = { |
| .ping_timeout = 50, |
| .classes = nullptr, |
| .classes_len = 2, |
| }; |
| |
| EXPECT_EQ(dif_alert_handler_configure(&alert_handler_, config), kDifBadArg); |
| } |
| |
| TEST_F(ConfigTest, ClassInit) { |
| std::vector<dif_alert_handler_alert_t> alerts_a = {1, 2, 5}; |
| std::vector<dif_alert_handler_local_alert_t> locals_a = { |
| kDifAlertHandlerLocalAlertEscalationPingFail, |
| }; |
| std::vector<dif_alert_handler_class_phase_signal_t> signals_a = { |
| {.phase = kDifAlertHandlerClassStatePhase0, .signal = 3}, |
| {.phase = kDifAlertHandlerClassStatePhase2, .signal = 1}, |
| }; |
| std::vector<dif_alert_handler_class_phase_duration_t> durations_a = { |
| {.phase = kDifAlertHandlerClassStatePhase1, .cycles = 20000}, |
| {.phase = kDifAlertHandlerClassStatePhase2, .cycles = 15000}, |
| }; |
| |
| std::vector<dif_alert_handler_alert_t> alerts_b = {9, 6, 11}; |
| std::vector<dif_alert_handler_local_alert_t> locals_b = { |
| kDifAlertHandlerLocalAlertAlertPingFail, |
| kDifAlertHandlerLocalAlertAlertIntegrityFail, |
| }; |
| std::vector<dif_alert_handler_class_phase_signal_t> signals_b = { |
| {.phase = kDifAlertHandlerClassStatePhase1, .signal = 0}, |
| }; |
| std::vector<dif_alert_handler_class_phase_duration_t> durations_b = { |
| {.phase = kDifAlertHandlerClassStatePhase1, .cycles = 20000}, |
| {.phase = kDifAlertHandlerClassStatePhase2, .cycles = 15000}, |
| {.phase = kDifAlertHandlerClassStatePhase3, .cycles = 150000}, |
| }; |
| |
| std::vector<dif_alert_handler_class_config_t> classes = { |
| { |
| .alert_class = kDifAlertHandlerClassA, |
| .alerts = alerts_a.data(), |
| .alerts_len = alerts_a.size(), |
| .local_alerts = locals_a.data(), |
| .local_alerts_len = locals_a.size(), |
| .use_escalation_protocol = kDifToggleDisabled, |
| .automatic_locking = kDifToggleEnabled, |
| .accumulator_threshold = 12, |
| .irq_deadline_cycles = 30000, |
| .phase_signals = signals_a.data(), |
| .phase_signals_len = signals_a.size(), |
| .phase_durations = durations_a.data(), |
| .phase_durations_len = durations_a.size(), |
| }, |
| { |
| .alert_class = kDifAlertHandlerClassB, |
| .alerts = alerts_b.data(), |
| .alerts_len = alerts_b.size(), |
| .local_alerts = locals_b.data(), |
| .local_alerts_len = locals_b.size(), |
| .use_escalation_protocol = kDifToggleEnabled, |
| .automatic_locking = kDifToggleDisabled, |
| .accumulator_threshold = 8, |
| .irq_deadline_cycles = 2000, |
| .phase_signals = signals_b.data(), |
| .phase_signals_len = signals_b.size(), |
| .phase_durations = durations_b.data(), |
| .phase_durations_len = durations_b.size(), |
| }, |
| }; |
| |
| dif_alert_handler_config_t config = { |
| .ping_timeout = 50, |
| .classes = classes.data(), |
| .classes_len = classes.size(), |
| }; |
| |
| // The alert handler needs to be unlocked for it to be configured. |
| EXPECT_READ32( |
| ALERT_HANDLER_PING_TIMER_EN_SHADOWED_REG_OFFSET, |
| {{ALERT_HANDLER_PING_TIMER_EN_SHADOWED_PING_TIMER_EN_SHADOWED_BIT, |
| false}}); |
| |
| // Configure class A alerts. |
| // Unfortunately, we can't use EXPECT_MASK for these reads/writes, since the |
| // target registers are shadowed. |
| for (auto alert : alerts_a) { |
| // The various alerts should be enabled. |
| ptrdiff_t alert_enable_reg_offset = |
| ALERT_HANDLER_ALERT_EN_SHADOWED_0_REG_OFFSET + alert * sizeof(uint32_t); |
| EXPECT_READ32(alert_enable_reg_offset, 0); |
| EXPECT_WRITE32_SHADOWED( |
| alert_enable_reg_offset, |
| {{ALERT_HANDLER_ALERT_EN_SHADOWED_0_EN_A_0_BIT, true}}); |
| // The various alerts should be classified. |
| ptrdiff_t alert_class_reg_offset = |
| ALERT_HANDLER_ALERT_CLASS_SHADOWED_0_REG_OFFSET + |
| alert * sizeof(uint32_t); |
| EXPECT_READ32(alert_class_reg_offset, 0); |
| EXPECT_WRITE32_SHADOWED( |
| alert_class_reg_offset, |
| ALERT_HANDLER_ALERT_CLASS_SHADOWED_0_CLASS_A_0_VALUE_CLASSA); |
| } |
| |
| // Configure class A local alerts. |
| // Unfortunately, we can't use EXPECT_MASK for these reads/writes, since the |
| // target registers are shadowed. |
| EXPECT_READ32(ALERT_HANDLER_LOC_ALERT_EN_SHADOWED_1_REG_OFFSET, |
| ALERT_HANDLER_LOC_ALERT_EN_SHADOWED_1_REG_RESVAL); |
| EXPECT_READ32(ALERT_HANDLER_LOC_ALERT_CLASS_SHADOWED_1_REG_OFFSET, |
| ALERT_HANDLER_LOC_ALERT_CLASS_SHADOWED_1_REG_RESVAL); |
| EXPECT_WRITE32_SHADOWED( |
| ALERT_HANDLER_LOC_ALERT_EN_SHADOWED_1_REG_OFFSET, |
| {{ALERT_HANDLER_LOC_ALERT_EN_SHADOWED_1_EN_LA_1_BIT, true}}); |
| EXPECT_WRITE32_SHADOWED( |
| ALERT_HANDLER_LOC_ALERT_CLASS_SHADOWED_1_REG_OFFSET, |
| ALERT_HANDLER_LOC_ALERT_CLASS_SHADOWED_0_CLASS_LA_0_VALUE_CLASSA); |
| |
| // Configure class A control register. |
| EXPECT_WRITE32_SHADOWED( |
| ALERT_HANDLER_CLASSA_CTRL_SHADOWED_REG_OFFSET, |
| { |
| {ALERT_HANDLER_CLASSA_CTRL_SHADOWED_EN_BIT, false}, |
| {ALERT_HANDLER_CLASSA_CTRL_SHADOWED_LOCK_BIT, true}, |
| {ALERT_HANDLER_CLASSA_CTRL_SHADOWED_EN_E0_BIT, true}, |
| {ALERT_HANDLER_CLASSA_CTRL_SHADOWED_MAP_E0_OFFSET, 3}, |
| {ALERT_HANDLER_CLASSA_CTRL_SHADOWED_EN_E2_BIT, true}, |
| {ALERT_HANDLER_CLASSA_CTRL_SHADOWED_MAP_E2_OFFSET, 1}, |
| }); |
| |
| EXPECT_WRITE32_SHADOWED(ALERT_HANDLER_CLASSA_ACCUM_THRESH_SHADOWED_REG_OFFSET, |
| 12); |
| EXPECT_WRITE32_SHADOWED(ALERT_HANDLER_CLASSA_TIMEOUT_CYC_SHADOWED_REG_OFFSET, |
| 30000); |
| |
| EXPECT_WRITE32_SHADOWED(ALERT_HANDLER_CLASSA_PHASE1_CYC_SHADOWED_REG_OFFSET, |
| 20000); |
| EXPECT_WRITE32_SHADOWED(ALERT_HANDLER_CLASSA_PHASE2_CYC_SHADOWED_REG_OFFSET, |
| 15000); |
| |
| // Configure class B alerts. |
| // Unfortunately, we can't use EXPECT_MASK for these reads/writes, since the |
| // target registers are shadowed. |
| for (auto alert : alerts_b) { |
| // The various alerts should be enabled. |
| ptrdiff_t alert_enable_reg_offset = |
| ALERT_HANDLER_ALERT_EN_SHADOWED_0_REG_OFFSET + alert * sizeof(uint32_t); |
| EXPECT_READ32(alert_enable_reg_offset, 0); |
| EXPECT_WRITE32_SHADOWED( |
| alert_enable_reg_offset, |
| {{ALERT_HANDLER_ALERT_EN_SHADOWED_0_EN_A_0_BIT, true}}); |
| // The various alerts should be classified. |
| ptrdiff_t alert_class_reg_offset = |
| ALERT_HANDLER_ALERT_CLASS_SHADOWED_0_REG_OFFSET + |
| alert * sizeof(uint32_t); |
| EXPECT_READ32(alert_class_reg_offset, 0); |
| EXPECT_WRITE32_SHADOWED( |
| alert_class_reg_offset, |
| ALERT_HANDLER_ALERT_CLASS_SHADOWED_0_CLASS_A_0_VALUE_CLASSB); |
| } |
| |
| // Configure class B local alerts. |
| // Unfortunately, we can't use EXPECT_MASK for these reads/writes, since the |
| // target registers are shadowed. |
| EXPECT_READ32(ALERT_HANDLER_LOC_ALERT_EN_SHADOWED_0_REG_OFFSET, |
| ALERT_HANDLER_LOC_ALERT_EN_SHADOWED_0_REG_RESVAL); |
| EXPECT_READ32(ALERT_HANDLER_LOC_ALERT_CLASS_SHADOWED_0_REG_OFFSET, |
| ALERT_HANDLER_LOC_ALERT_CLASS_SHADOWED_0_REG_RESVAL); |
| EXPECT_WRITE32_SHADOWED( |
| ALERT_HANDLER_LOC_ALERT_EN_SHADOWED_0_REG_OFFSET, |
| {{ALERT_HANDLER_LOC_ALERT_EN_SHADOWED_0_EN_LA_0_BIT, true}}); |
| EXPECT_WRITE32_SHADOWED( |
| ALERT_HANDLER_LOC_ALERT_CLASS_SHADOWED_0_REG_OFFSET, |
| ALERT_HANDLER_LOC_ALERT_CLASS_SHADOWED_0_CLASS_LA_0_VALUE_CLASSB); |
| EXPECT_READ32(ALERT_HANDLER_LOC_ALERT_EN_SHADOWED_2_REG_OFFSET, |
| ALERT_HANDLER_LOC_ALERT_EN_SHADOWED_2_REG_RESVAL); |
| EXPECT_READ32(ALERT_HANDLER_LOC_ALERT_CLASS_SHADOWED_2_REG_OFFSET, |
| ALERT_HANDLER_LOC_ALERT_CLASS_SHADOWED_2_REG_RESVAL); |
| EXPECT_WRITE32_SHADOWED( |
| ALERT_HANDLER_LOC_ALERT_EN_SHADOWED_2_REG_OFFSET, |
| {{ALERT_HANDLER_LOC_ALERT_EN_SHADOWED_2_EN_LA_2_BIT, true}}); |
| EXPECT_WRITE32_SHADOWED( |
| ALERT_HANDLER_LOC_ALERT_CLASS_SHADOWED_2_REG_OFFSET, |
| ALERT_HANDLER_LOC_ALERT_CLASS_SHADOWED_0_CLASS_LA_0_VALUE_CLASSB); |
| |
| // Configure class B control register. |
| EXPECT_WRITE32_SHADOWED( |
| ALERT_HANDLER_CLASSB_CTRL_SHADOWED_REG_OFFSET, |
| { |
| {ALERT_HANDLER_CLASSB_CTRL_SHADOWED_EN_BIT, true}, |
| {ALERT_HANDLER_CLASSB_CTRL_SHADOWED_LOCK_BIT, false}, |
| {ALERT_HANDLER_CLASSB_CTRL_SHADOWED_EN_E1_BIT, true}, |
| {ALERT_HANDLER_CLASSB_CTRL_SHADOWED_MAP_E1_OFFSET, 0}, |
| }); |
| |
| EXPECT_WRITE32_SHADOWED(ALERT_HANDLER_CLASSB_ACCUM_THRESH_SHADOWED_REG_OFFSET, |
| 8); |
| EXPECT_WRITE32_SHADOWED(ALERT_HANDLER_CLASSB_TIMEOUT_CYC_SHADOWED_REG_OFFSET, |
| 2000); |
| |
| EXPECT_WRITE32_SHADOWED(ALERT_HANDLER_CLASSB_PHASE1_CYC_SHADOWED_REG_OFFSET, |
| 20000); |
| EXPECT_WRITE32_SHADOWED(ALERT_HANDLER_CLASSB_PHASE2_CYC_SHADOWED_REG_OFFSET, |
| 15000); |
| EXPECT_WRITE32_SHADOWED(ALERT_HANDLER_CLASSB_PHASE3_CYC_SHADOWED_REG_OFFSET, |
| 150000); |
| |
| EXPECT_WRITE32_SHADOWED( |
| ALERT_HANDLER_PING_TIMEOUT_CYC_SHADOWED_REG_OFFSET, |
| {{ALERT_HANDLER_PING_TIMEOUT_CYC_SHADOWED_PING_TIMEOUT_CYC_SHADOWED_OFFSET, |
| 50}}); |
| |
| EXPECT_EQ(dif_alert_handler_configure(&alert_handler_, config), kDifOk); |
| } |
| |
| TEST_F(ConfigTest, BadAlert) { |
| IgnoreMmioCalls(); |
| |
| std::vector<dif_alert_handler_alert_t> alerts_a = {1, 2, kAlerts + 1}; |
| std::vector<dif_alert_handler_local_alert_t> locals_a = { |
| kDifAlertHandlerLocalAlertEscalationPingFail, |
| }; |
| std::vector<dif_alert_handler_class_phase_signal_t> signals_a = { |
| {.phase = kDifAlertHandlerClassStatePhase0, .signal = 3}, |
| {.phase = kDifAlertHandlerClassStatePhase2, .signal = 1}, |
| }; |
| std::vector<dif_alert_handler_class_phase_duration_t> durations_a = { |
| {.phase = kDifAlertHandlerClassStatePhase1, .cycles = 20000}, |
| {.phase = kDifAlertHandlerClassStatePhase2, .cycles = 15000}, |
| }; |
| |
| std::vector<dif_alert_handler_class_config_t> classes = { |
| { |
| .alert_class = kDifAlertHandlerClassA, |
| .alerts = alerts_a.data(), |
| .alerts_len = alerts_a.size(), |
| .local_alerts = locals_a.data(), |
| .local_alerts_len = locals_a.size(), |
| .use_escalation_protocol = kDifToggleDisabled, |
| .automatic_locking = kDifToggleEnabled, |
| .accumulator_threshold = 12, |
| .irq_deadline_cycles = 30000, |
| .phase_signals = signals_a.data(), |
| .phase_signals_len = signals_a.size(), |
| .phase_durations = durations_a.data(), |
| .phase_durations_len = durations_a.size(), |
| }, |
| }; |
| |
| dif_alert_handler_config_t config = { |
| .ping_timeout = 50, |
| .classes = classes.data(), |
| .classes_len = classes.size(), |
| }; |
| |
| EXPECT_EQ(dif_alert_handler_configure(&alert_handler_, config), kDifError); |
| } |
| |
| TEST_F(ConfigTest, BadSignalPhase) { |
| IgnoreMmioCalls(); |
| |
| std::vector<dif_alert_handler_alert_t> alerts_a = {1, 2, 5}; |
| std::vector<dif_alert_handler_local_alert_t> locals_a = { |
| kDifAlertHandlerLocalAlertEscalationPingFail, |
| }; |
| std::vector<dif_alert_handler_class_phase_signal_t> signals_a = { |
| {.phase = kDifAlertHandlerClassStatePhase0, .signal = 3}, |
| {.phase = kDifAlertHandlerClassStateTerminal, .signal = 1}, |
| }; |
| std::vector<dif_alert_handler_class_phase_duration_t> durations_a = { |
| {.phase = kDifAlertHandlerClassStatePhase1, .cycles = 20000}, |
| {.phase = kDifAlertHandlerClassStatePhase2, .cycles = 15000}, |
| }; |
| |
| std::vector<dif_alert_handler_class_config_t> classes = { |
| { |
| .alert_class = kDifAlertHandlerClassA, |
| .alerts = alerts_a.data(), |
| .alerts_len = alerts_a.size(), |
| .local_alerts = locals_a.data(), |
| .local_alerts_len = locals_a.size(), |
| .use_escalation_protocol = kDifToggleDisabled, |
| .automatic_locking = kDifToggleEnabled, |
| .accumulator_threshold = 12, |
| .irq_deadline_cycles = 30000, |
| .phase_signals = signals_a.data(), |
| .phase_signals_len = signals_a.size(), |
| .phase_durations = durations_a.data(), |
| .phase_durations_len = durations_a.size(), |
| }, |
| }; |
| |
| dif_alert_handler_config_t config = { |
| .ping_timeout = 50, |
| .classes = classes.data(), |
| .classes_len = classes.size(), |
| }; |
| |
| EXPECT_EQ(dif_alert_handler_configure(&alert_handler_, config), kDifError); |
| } |
| |
| TEST_F(ConfigTest, BadDurationPhase) { |
| IgnoreMmioCalls(); |
| |
| std::vector<dif_alert_handler_alert_t> alerts_a = {1, 2, 5}; |
| std::vector<dif_alert_handler_local_alert_t> locals_a = { |
| kDifAlertHandlerLocalAlertEscalationPingFail, |
| }; |
| std::vector<dif_alert_handler_class_phase_signal_t> signals_a = { |
| {.phase = kDifAlertHandlerClassStatePhase0, .signal = 3}, |
| {.phase = kDifAlertHandlerClassStatePhase2, .signal = 1}, |
| }; |
| std::vector<dif_alert_handler_class_phase_duration_t> durations_a = { |
| {.phase = kDifAlertHandlerClassStateTerminal, .cycles = 20000}, |
| {.phase = kDifAlertHandlerClassStatePhase2, .cycles = 15000}, |
| }; |
| |
| std::vector<dif_alert_handler_class_config_t> classes = { |
| { |
| .alert_class = kDifAlertHandlerClassA, |
| .alerts = alerts_a.data(), |
| .alerts_len = alerts_a.size(), |
| .local_alerts = locals_a.data(), |
| .local_alerts_len = locals_a.size(), |
| .use_escalation_protocol = kDifToggleDisabled, |
| .automatic_locking = kDifToggleEnabled, |
| .accumulator_threshold = 12, |
| .irq_deadline_cycles = 30000, |
| .phase_signals = signals_a.data(), |
| .phase_signals_len = signals_a.size(), |
| .phase_durations = durations_a.data(), |
| .phase_durations_len = durations_a.size(), |
| }, |
| }; |
| |
| dif_alert_handler_config_t config = { |
| .ping_timeout = 50, |
| .classes = classes.data(), |
| .classes_len = classes.size(), |
| }; |
| |
| EXPECT_EQ(dif_alert_handler_configure(&alert_handler_, config), kDifError); |
| } |
| |
| TEST_F(ConfigTest, BadPointers) { |
| IgnoreMmioCalls(); |
| |
| std::vector<dif_alert_handler_alert_t> alerts_a = {1, 2, 5}; |
| std::vector<dif_alert_handler_local_alert_t> locals_a = { |
| kDifAlertHandlerLocalAlertEscalationPingFail, |
| }; |
| std::vector<dif_alert_handler_class_phase_signal_t> signals_a = { |
| {.phase = kDifAlertHandlerClassStatePhase0, .signal = 3}, |
| {.phase = kDifAlertHandlerClassStatePhase2, .signal = 1}, |
| }; |
| std::vector<dif_alert_handler_class_phase_duration_t> durations_a = { |
| {.phase = kDifAlertHandlerClassStateTerminal, .cycles = 20000}, |
| {.phase = kDifAlertHandlerClassStatePhase2, .cycles = 15000}, |
| }; |
| |
| std::vector<dif_alert_handler_class_config_t> classes = { |
| { |
| .alert_class = kDifAlertHandlerClassA, |
| .alerts = alerts_a.data(), |
| .alerts_len = alerts_a.size(), |
| .local_alerts = locals_a.data(), |
| .local_alerts_len = locals_a.size(), |
| .use_escalation_protocol = kDifToggleDisabled, |
| .automatic_locking = kDifToggleEnabled, |
| .accumulator_threshold = 12, |
| .irq_deadline_cycles = 30000, |
| .phase_signals = signals_a.data(), |
| .phase_signals_len = signals_a.size(), |
| .phase_durations = durations_a.data(), |
| .phase_durations_len = durations_a.size(), |
| }, |
| }; |
| |
| dif_alert_handler_config_t config = { |
| .ping_timeout = 50, |
| .classes = classes.data(), |
| .classes_len = classes.size(), |
| }; |
| |
| classes[0].alerts = nullptr; |
| EXPECT_EQ(dif_alert_handler_configure(&alert_handler_, config), kDifError); |
| classes[0].alerts = alerts_a.data(); |
| |
| classes[0].local_alerts = nullptr; |
| EXPECT_EQ(dif_alert_handler_configure(&alert_handler_, config), kDifError); |
| classes[0].local_alerts = locals_a.data(); |
| |
| classes[0].phase_signals = nullptr; |
| EXPECT_EQ(dif_alert_handler_configure(&alert_handler_, config), kDifError); |
| classes[0].phase_signals = signals_a.data(); |
| |
| classes[0].phase_durations = nullptr; |
| EXPECT_EQ(dif_alert_handler_configure(&alert_handler_, config), kDifError); |
| } |
| |
| TEST_F(ConfigTest, BadClass) { |
| IgnoreMmioCalls(); |
| |
| std::vector<dif_alert_handler_alert_t> alerts_a = {1, 2, 5}; |
| std::vector<dif_alert_handler_local_alert_t> locals_a = { |
| kDifAlertHandlerLocalAlertEscalationPingFail, |
| }; |
| std::vector<dif_alert_handler_class_phase_signal_t> signals_a = { |
| {.phase = kDifAlertHandlerClassStatePhase0, .signal = 3}, |
| {.phase = kDifAlertHandlerClassStatePhase2, .signal = 1}, |
| }; |
| std::vector<dif_alert_handler_class_phase_duration_t> durations_a = { |
| {.phase = kDifAlertHandlerClassStatePhase0, .cycles = 20000}, |
| {.phase = kDifAlertHandlerClassStatePhase2, .cycles = 15000}, |
| }; |
| |
| std::vector<dif_alert_handler_class_config_t> classes = { |
| { |
| .alert_class = static_cast<dif_alert_handler_class_t>(12), |
| .alerts = alerts_a.data(), |
| .alerts_len = alerts_a.size(), |
| .local_alerts = locals_a.data(), |
| .local_alerts_len = locals_a.size(), |
| .use_escalation_protocol = kDifToggleDisabled, |
| .automatic_locking = kDifToggleEnabled, |
| .accumulator_threshold = 12, |
| .irq_deadline_cycles = 30000, |
| .phase_signals = signals_a.data(), |
| .phase_signals_len = signals_a.size(), |
| .phase_durations = durations_a.data(), |
| .phase_durations_len = durations_a.size(), |
| }, |
| }; |
| |
| dif_alert_handler_config_t config = { |
| .ping_timeout = 50, |
| .classes = classes.data(), |
| .classes_len = classes.size(), |
| }; |
| |
| EXPECT_EQ(dif_alert_handler_configure(&alert_handler_, config), kDifError); |
| } |
| |
| TEST_F(ConfigTest, NullArgs) { |
| EXPECT_EQ(dif_alert_handler_configure(nullptr, {}), kDifBadArg); |
| } |
| |
| class LockTest : public AlertHandlerTest {}; |
| |
| TEST_F(LockTest, IsLocked) { |
| bool flag; |
| |
| EXPECT_READ32( |
| ALERT_HANDLER_PING_TIMER_EN_SHADOWED_REG_OFFSET, |
| {{ALERT_HANDLER_PING_TIMER_EN_SHADOWED_PING_TIMER_EN_SHADOWED_BIT, |
| false}}); |
| EXPECT_EQ(dif_alert_handler_is_locked(&alert_handler_, &flag), kDifOk); |
| EXPECT_FALSE(flag); |
| |
| EXPECT_READ32( |
| ALERT_HANDLER_PING_TIMER_EN_SHADOWED_REG_OFFSET, |
| {{ALERT_HANDLER_PING_TIMER_EN_SHADOWED_PING_TIMER_EN_SHADOWED_BIT, |
| true}}); |
| EXPECT_EQ(dif_alert_handler_is_locked(&alert_handler_, &flag), kDifOk); |
| EXPECT_TRUE(flag); |
| } |
| |
| TEST_F(LockTest, Lock) { |
| EXPECT_WRITE32_SHADOWED( |
| ALERT_HANDLER_PING_TIMER_EN_SHADOWED_REG_OFFSET, |
| {{ALERT_HANDLER_PING_TIMER_EN_SHADOWED_PING_TIMER_EN_SHADOWED_BIT, |
| true}}); |
| EXPECT_EQ(dif_alert_handler_lock(&alert_handler_), kDifOk); |
| } |
| |
| TEST_F(LockTest, NullArgs) { |
| bool flag; |
| EXPECT_EQ(dif_alert_handler_is_locked(nullptr, &flag), kDifBadArg); |
| EXPECT_EQ(dif_alert_handler_is_locked(&alert_handler_, nullptr), kDifBadArg); |
| |
| EXPECT_EQ(dif_alert_handler_lock(nullptr), kDifBadArg); |
| } |
| |
| class CauseTest : public AlertHandlerTest {}; |
| |
| TEST_F(CauseTest, IsCause) { |
| bool flag; |
| |
| EXPECT_READ32(ALERT_HANDLER_ALERT_CAUSE_5_REG_OFFSET, {{0, true}}); |
| EXPECT_EQ(dif_alert_handler_alert_is_cause(&alert_handler_, 5, &flag), |
| kDifOk); |
| EXPECT_TRUE(flag); |
| |
| EXPECT_READ32(ALERT_HANDLER_ALERT_CAUSE_6_REG_OFFSET, {{0, false}}); |
| EXPECT_EQ(dif_alert_handler_alert_is_cause(&alert_handler_, 6, &flag), |
| kDifOk); |
| EXPECT_FALSE(flag); |
| } |
| |
| TEST_F(CauseTest, Ack) { |
| EXPECT_WRITE32(ALERT_HANDLER_ALERT_CAUSE_0_REG_OFFSET, |
| {{ALERT_HANDLER_ALERT_CAUSE_0_A_0_BIT, true}}); |
| EXPECT_EQ(dif_alert_handler_alert_acknowledge(&alert_handler_, 0), kDifOk); |
| |
| EXPECT_WRITE32(ALERT_HANDLER_ALERT_CAUSE_11_REG_OFFSET, |
| {{ALERT_HANDLER_ALERT_CAUSE_11_A_11_BIT, true}}); |
| EXPECT_EQ(dif_alert_handler_alert_acknowledge(&alert_handler_, 11), kDifOk); |
| } |
| |
| TEST_F(CauseTest, BadAlert) { |
| bool flag; |
| EXPECT_EQ(dif_alert_handler_alert_is_cause(&alert_handler_, kAlerts, &flag), |
| kDifBadArg); |
| EXPECT_EQ(dif_alert_handler_alert_acknowledge(&alert_handler_, kAlerts), |
| kDifBadArg); |
| } |
| |
| TEST_F(CauseTest, IsCauseLocal) { |
| bool flag; |
| |
| EXPECT_READ32(ALERT_HANDLER_LOC_ALERT_CAUSE_1_REG_OFFSET, |
| {{ALERT_HANDLER_LOC_ALERT_CAUSE_1_LA_1_BIT, true}}); |
| EXPECT_EQ( |
| dif_alert_handler_local_alert_is_cause( |
| &alert_handler_, kDifAlertHandlerLocalAlertEscalationPingFail, &flag), |
| kDifOk); |
| EXPECT_TRUE(flag); |
| |
| EXPECT_READ32(ALERT_HANDLER_LOC_ALERT_CAUSE_4_REG_OFFSET, |
| {{ALERT_HANDLER_LOC_ALERT_CAUSE_4_LA_4_BIT, true}}); |
| EXPECT_EQ( |
| dif_alert_handler_local_alert_is_cause( |
| &alert_handler_, kDifAlertHandlerLocalAlertBusIntegrityFail, &flag), |
| kDifOk); |
| EXPECT_TRUE(flag); |
| |
| EXPECT_READ32(ALERT_HANDLER_LOC_ALERT_CAUSE_3_REG_OFFSET, |
| {{ALERT_HANDLER_LOC_ALERT_CAUSE_3_LA_3_BIT, false}}); |
| EXPECT_EQ(dif_alert_handler_local_alert_is_cause( |
| &alert_handler_, |
| kDifAlertHandlerLocalAlertEscalationIntegrityFail, &flag), |
| kDifOk); |
| EXPECT_FALSE(flag); |
| } |
| |
| TEST_F(CauseTest, AckLocal) { |
| EXPECT_WRITE32(ALERT_HANDLER_LOC_ALERT_CAUSE_3_REG_OFFSET, |
| {{ALERT_HANDLER_LOC_ALERT_CAUSE_3_LA_3_BIT, true}}); |
| EXPECT_EQ( |
| dif_alert_handler_local_alert_acknowledge( |
| &alert_handler_, kDifAlertHandlerLocalAlertEscalationIntegrityFail), |
| kDifOk); |
| |
| EXPECT_WRITE32(ALERT_HANDLER_LOC_ALERT_CAUSE_4_REG_OFFSET, |
| {{ALERT_HANDLER_LOC_ALERT_CAUSE_4_LA_4_BIT, true}}); |
| EXPECT_EQ(dif_alert_handler_local_alert_acknowledge( |
| &alert_handler_, kDifAlertHandlerLocalAlertBusIntegrityFail), |
| kDifOk); |
| } |
| |
| TEST_F(CauseTest, NullArgs) { |
| bool flag; |
| EXPECT_EQ(dif_alert_handler_alert_is_cause(nullptr, 5, &flag), kDifBadArg); |
| EXPECT_EQ(dif_alert_handler_alert_is_cause(&alert_handler_, 5, nullptr), |
| kDifBadArg); |
| EXPECT_EQ(dif_alert_handler_alert_acknowledge(nullptr, 11), kDifBadArg); |
| EXPECT_EQ(dif_alert_handler_local_alert_is_cause( |
| nullptr, kDifAlertHandlerLocalAlertEscalationPingFail, &flag), |
| kDifBadArg); |
| EXPECT_EQ(dif_alert_handler_local_alert_is_cause( |
| &alert_handler_, kDifAlertHandlerLocalAlertEscalationPingFail, |
| nullptr), |
| kDifBadArg); |
| EXPECT_EQ(dif_alert_handler_local_alert_acknowledge( |
| nullptr, kDifAlertHandlerLocalAlertEscalationIntegrityFail), |
| kDifBadArg); |
| } |
| |
| class EscalationTest : public AlertHandlerTest {}; |
| |
| TEST_F(EscalationTest, CanClear) { |
| bool flag; |
| |
| EXPECT_READ32(ALERT_HANDLER_CLASSB_CLR_REGWEN_REG_OFFSET, true); |
| EXPECT_EQ(dif_alert_handler_escalation_can_clear( |
| &alert_handler_, kDifAlertHandlerClassB, &flag), |
| kDifOk); |
| EXPECT_TRUE(flag); |
| |
| EXPECT_READ32(ALERT_HANDLER_CLASSA_CLR_REGWEN_REG_OFFSET, false); |
| EXPECT_EQ(dif_alert_handler_escalation_can_clear( |
| &alert_handler_, kDifAlertHandlerClassA, &flag), |
| kDifOk); |
| EXPECT_FALSE(flag); |
| } |
| |
| TEST_F(EscalationTest, Disable) { |
| EXPECT_WRITE32(ALERT_HANDLER_CLASSC_CLR_REGWEN_REG_OFFSET, true); |
| EXPECT_EQ(dif_alert_handler_escalation_disable_clearing( |
| &alert_handler_, kDifAlertHandlerClassC), |
| kDifOk); |
| } |
| |
| TEST_F(EscalationTest, Clear) { |
| EXPECT_WRITE32_SHADOWED(ALERT_HANDLER_CLASSD_CLR_SHADOWED_REG_OFFSET, true); |
| EXPECT_EQ(dif_alert_handler_escalation_clear(&alert_handler_, |
| kDifAlertHandlerClassD), |
| kDifOk); |
| } |
| |
| TEST_F(EscalationTest, NullArgs) { |
| bool flag; |
| |
| EXPECT_EQ(dif_alert_handler_escalation_can_clear( |
| nullptr, kDifAlertHandlerClassB, &flag), |
| kDifBadArg); |
| EXPECT_EQ(dif_alert_handler_escalation_can_clear( |
| &alert_handler_, kDifAlertHandlerClassB, nullptr), |
| kDifBadArg); |
| EXPECT_EQ(dif_alert_handler_escalation_disable_clearing( |
| nullptr, kDifAlertHandlerClassC), |
| kDifBadArg); |
| EXPECT_EQ(dif_alert_handler_escalation_clear(nullptr, kDifAlertHandlerClassD), |
| kDifBadArg); |
| } |
| |
| class GetterTest : public AlertHandlerTest {}; |
| |
| TEST_F(GetterTest, GetAcc) { |
| uint16_t alerts; |
| EXPECT_READ32(ALERT_HANDLER_CLASSB_ACCUM_CNT_REG_OFFSET, 0xaaaa); |
| EXPECT_EQ(dif_alert_handler_get_accumulator(&alert_handler_, |
| kDifAlertHandlerClassB, &alerts), |
| kDifOk); |
| EXPECT_EQ(alerts, 0xaaaa); |
| } |
| |
| TEST_F(GetterTest, GetCycles) { |
| uint32_t cycles; |
| EXPECT_READ32(ALERT_HANDLER_CLASSD_ESC_CNT_REG_OFFSET, 0xaaaaaaaa); |
| EXPECT_EQ(dif_alert_handler_get_escalation_counter( |
| &alert_handler_, kDifAlertHandlerClassD, &cycles), |
| kDifOk); |
| EXPECT_EQ(cycles, 0xaaaaaaaa); |
| } |
| |
| TEST_F(GetterTest, GetState) { |
| dif_alert_handler_class_state_t state; |
| |
| EXPECT_READ32(ALERT_HANDLER_CLASSC_STATE_REG_OFFSET, |
| ALERT_HANDLER_CLASSA_STATE_CLASSA_STATE_VALUE_TIMEOUT); |
| EXPECT_EQ(dif_alert_handler_get_class_state(&alert_handler_, |
| kDifAlertHandlerClassC, &state), |
| kDifOk); |
| EXPECT_EQ(state, kDifAlertHandlerClassStateTimeout); |
| |
| EXPECT_READ32(ALERT_HANDLER_CLASSA_STATE_REG_OFFSET, |
| ALERT_HANDLER_CLASSA_STATE_CLASSA_STATE_VALUE_PHASE2); |
| EXPECT_EQ(dif_alert_handler_get_class_state(&alert_handler_, |
| kDifAlertHandlerClassA, &state), |
| kDifOk); |
| EXPECT_EQ(state, kDifAlertHandlerClassStatePhase2); |
| } |
| |
| TEST_F(GetterTest, NullArgs) { |
| uint16_t alerts; |
| EXPECT_EQ(dif_alert_handler_get_accumulator(nullptr, kDifAlertHandlerClassB, |
| &alerts), |
| kDifBadArg); |
| EXPECT_EQ(dif_alert_handler_get_accumulator(&alert_handler_, |
| kDifAlertHandlerClassB, nullptr), |
| kDifBadArg); |
| |
| uint32_t cycles; |
| EXPECT_EQ(dif_alert_handler_get_escalation_counter( |
| nullptr, kDifAlertHandlerClassB, &cycles), |
| kDifBadArg); |
| EXPECT_EQ(dif_alert_handler_get_escalation_counter( |
| &alert_handler_, kDifAlertHandlerClassB, nullptr), |
| kDifBadArg); |
| |
| dif_alert_handler_class_state_t state; |
| EXPECT_EQ(dif_alert_handler_get_class_state(nullptr, kDifAlertHandlerClassC, |
| &state), |
| kDifBadArg); |
| EXPECT_EQ(dif_alert_handler_get_class_state(&alert_handler_, |
| kDifAlertHandlerClassC, nullptr), |
| kDifBadArg); |
| } |
| |
| } // namespace |
| } // namespace dif_alert_handler_unittest |