From bf6fbc2121d1e9620d1be0b02e78146cc43eabb4 Mon Sep 17 00:00:00 2001 From: Andrea Caforio <andrea.caforio@lowrisc.org> Date: Thu, 12 Dec 2024 12:45:38 +0100 Subject: [PATCH] [alert, sival] chip_sw_alert_handler_escalation This commit generalizes the existing `alert_handler_escalation_test` to all simulation targets to cover the `chip_sw_alert_handler_escalation` testplan item (as specified in `hw/top_earlgrey/data/ip/chip_alert_handler_testplan.hjson`). Signed-off-by: Andrea Caforio <andrea.caforio@lowrisc.org> --- .../data/ip/chip_alert_handler_testplan.hjson | 2 +- hw/top_earlgrey/dv/chip_sim_cfg.hjson | 2 +- sw/device/tests/BUILD | 35 +++++ ...tion.c => alert_handler_escalation_test.c} | 142 +++++++++++------- sw/device/tests/sim_dv/BUILD | 25 --- 5 files changed, 123 insertions(+), 83 deletions(-) rename sw/device/tests/{sim_dv/alert_handler_escalation.c => alert_handler_escalation_test.c} (55%) diff --git a/hw/top_earlgrey/data/ip/chip_alert_handler_testplan.hjson b/hw/top_earlgrey/data/ip/chip_alert_handler_testplan.hjson index 971109772d61d..8e8b34f77bccf 100644 --- a/hw/top_earlgrey/data/ip/chip_alert_handler_testplan.hjson +++ b/hw/top_earlgrey/data/ip/chip_alert_handler_testplan.hjson @@ -43,7 +43,7 @@ si_stage: SV3 lc_states: ["PROD"] tests: ["chip_sw_alert_handler_escalation"] - bazel: [] + bazel: ["//sw/device/tests:alert_handler_escalation_test"] otp_mutate: true host_support: true } diff --git a/hw/top_earlgrey/dv/chip_sim_cfg.hjson b/hw/top_earlgrey/dv/chip_sim_cfg.hjson index 4a03f59d24ffe..9f53798d59cef 100644 --- a/hw/top_earlgrey/dv/chip_sim_cfg.hjson +++ b/hw/top_earlgrey/dv/chip_sim_cfg.hjson @@ -1308,7 +1308,7 @@ { name: chip_sw_alert_handler_escalation uvm_test_seq: chip_sw_alert_handler_escalation_vseq - sw_images: ["//sw/device/tests/sim_dv:alert_handler_escalation_test:1:new_rules"] + sw_images: ["//sw/device/tests:alert_handler_escalation_test:1:new_rules"] en_run_modes: ["sw_test_mode_test_rom"] // Disable scoreboard to avoid incorrect alert prediction from the alert_monitor. Due to the // cross-domain alert senders and receivers, the monitor from the chip level did not support diff --git a/sw/device/tests/BUILD b/sw/device/tests/BUILD index 724cc3d9f8dd0..9c189d2efe7ef 100644 --- a/sw/device/tests/BUILD +++ b/sw/device/tests/BUILD @@ -277,6 +277,41 @@ opentitan_test( ], ) +opentitan_test( + name = "alert_handler_escalation_test", + srcs = ["alert_handler_escalation_test.c"], + exec_env = dicts.add( + EARLGREY_TEST_ENVS, + EARLGREY_SILICON_OWNER_ROM_EXT_ENVS, + { + "//hw/top_earlgrey:fpga_cw310_sival": None, + "//hw/top_earlgrey:silicon_creator": None, + }, + ), + verilator = verilator_params( + timeout = "long", + ), + deps = [ + "//hw/top_earlgrey:alert_handler_c_regs", + "//hw/top_earlgrey/sw/autogen:top_earlgrey", + "//sw/device/lib/arch:device", + "//sw/device/lib/base:memory", + "//sw/device/lib/base:mmio", + "//sw/device/lib/dif:alert_handler", + "//sw/device/lib/dif:clkmgr", + "//sw/device/lib/dif:keymgr", + "//sw/device/lib/dif:rstmgr", + "//sw/device/lib/dif:rv_core_ibex", + "//sw/device/lib/runtime:hart", + "//sw/device/lib/runtime:ibex", + "//sw/device/lib/runtime:log", + "//sw/device/lib/testing:alert_handler_testutils", + "//sw/device/lib/testing:keymgr_testutils", + "//sw/device/lib/testing:rstmgr_testutils", + "//sw/device/lib/testing/test_framework:ottf_main", + ], +) + opentitan_test( name = "alert_handler_ping_timeout_test", srcs = ["alert_handler_ping_timeout_test.c"], diff --git a/sw/device/tests/sim_dv/alert_handler_escalation.c b/sw/device/tests/alert_handler_escalation_test.c similarity index 55% rename from sw/device/tests/sim_dv/alert_handler_escalation.c rename to sw/device/tests/alert_handler_escalation_test.c index 45e7b8669b0ee..015ae75355a2c 100644 --- a/sw/device/tests/sim_dv/alert_handler_escalation.c +++ b/sw/device/tests/alert_handler_escalation_test.c @@ -23,18 +23,6 @@ #include "hw/top_earlgrey/sw/autogen/top_earlgrey.h" #include "rv_core_ibex_regs.h" // Generated. -/* - - Verify the first escalation results in NMI interrupt serviced by the CPU. - - Verify the second results in device being put in escalate state, via the LC - JTAG TAP. - - Verify the third results in chip reset. - - Ensure that all escalation handshakes complete without errors. - - The first escalation is checked via the entry of the NMI handler and polling - by dv. The second escalation is directly checked by dv. The third escalation - is checked via reset reason. - */ - OTTF_DEFINE_TEST_CONFIG(); static dif_clkmgr_t clkmgr; @@ -44,47 +32,33 @@ static dif_alert_handler_t alert_handler; static dif_rv_core_ibex_t rv_core_ibex; static dif_uart_t uart; -typedef struct node { - const char *name; - dif_alert_handler_alert_t alert; - dif_alert_handler_class_t class; -} node_t; - -static const dif_alert_handler_escalation_phase_t kEscProfiles[] = { - // TODO: - // this first/second duration must be long enough to - // accommodate a jtag transaction - // how can this be done in a non-hardcoded way? - {.phase = kDifAlertHandlerClassStatePhase0, - .signal = 0, - .duration_cycles = 10000}, - {.phase = kDifAlertHandlerClassStatePhase1, - .signal = 1, - .duration_cycles = 10000}, - {.phase = kDifAlertHandlerClassStatePhase2, - .signal = 3, - .duration_cycles = 3000}}; - -static const dif_alert_handler_class_config_t kConfigProfiles[] = {{ - .auto_lock_accumulation_counter = kDifToggleDisabled, - .accumulator_threshold = 0, - .irq_deadline_cycles = 0, - .escalation_phases = kEscProfiles, - .escalation_phases_len = 3, - .crashdump_escalation_phase = kDifAlertHandlerClassStatePhase1, -}}; - /** * External ISR. * * Handles all peripheral interrupts on Ibex. PLIC asserts an external interrupt * line to the CPU, which results in a call to this OTTF ISR. This ISR * overrides the default OTTF implementation. + * + * @param exc_info Execution info. */ void ottf_external_nmi_handler(uint32_t *exc_info) { // DO NOT REMOVE, DV sync message LOG_INFO("You are experiencing an NMI"); + dif_rv_core_ibex_nmi_state_t nmi_state = (dif_rv_core_ibex_nmi_state_t){0}; + + CHECK_DIF_OK(dif_rv_core_ibex_get_nmi_state( + &rv_core_ibex, (dif_rv_core_ibex_nmi_state_t *)&nmi_state)); + + CHECK(nmi_state.alert_enabled && nmi_state.alert_raised, + "Alert handler NMI state not expected:\n\t" + "alert_enable:%x\n\talert_raised:%x\n", + nmi_state.alert_enabled, nmi_state.alert_raised); + + dif_alert_handler_class_state_t state; + CHECK_DIF_OK(dif_alert_handler_get_class_state( + &alert_handler, kDifAlertHandlerClassA, &state)); + // Now intentionally hang the device CHECK_DIF_OK(dif_clkmgr_gateable_clock_set_enabled( &clkmgr, kTopEarlgreyGateableClocksIoDiv4Peri, kDifToggleDisabled)); @@ -94,7 +68,10 @@ void ottf_external_nmi_handler(uint32_t *exc_info) { LOG_FATAL("This message should never be seen"); } -bool test_main(void) { +/** + * Initialize the dif handles required for this test. + */ +static void init_peripheral_handles(void) { CHECK_DIF_OK(dif_clkmgr_init( mmio_region_from_addr(TOP_EARLGREY_CLKMGR_AON_BASE_ADDR), &clkmgr)); @@ -114,6 +91,71 @@ bool test_main(void) { CHECK_DIF_OK(dif_keymgr_init( mmio_region_from_addr(TOP_EARLGREY_KEYMGR_BASE_ADDR), &keymgr)); +} + +/** + * Configure the alert handler. The escalation phases (NMI interrupt, LC scrap + * state, chip reset) are assigned to alert class A. + */ +static void config_alert_handler(void) { + // Escalation phase 0 is the NMI interrupt whose timeout value before + // progressing to phase 1 differs depending on the simulation device. For + // example, on the ChipWhisperer 1000000 cycles are enough to prevent a + // premature cancellation of the NMI interrupt handler (see + // `ottf_external_nmi_handler`). + uint32_t phase0DurationCycles = 1000000; + if (kDeviceType == kDeviceSimVerilator) { + phase0DurationCycles /= 10; + } else if (kDeviceType == kDeviceSimDV) { + phase0DurationCycles /= 100; + } + + dif_alert_handler_escalation_phase_t escalationProfiles[] = { + {.phase = kDifAlertHandlerClassStatePhase0, + .signal = 0, + .duration_cycles = phase0DurationCycles}, + {.phase = kDifAlertHandlerClassStatePhase1, + .signal = 1, + .duration_cycles = 10000}, + {.phase = kDifAlertHandlerClassStatePhase2, + .signal = 3, + .duration_cycles = 10000}, + }; + dif_alert_handler_class_config_t configProfiles[] = {{ + .auto_lock_accumulation_counter = kDifToggleDisabled, + .accumulator_threshold = 0, + .irq_deadline_cycles = 0, + .escalation_phases = escalationProfiles, + .escalation_phases_len = 3, + .crashdump_escalation_phase = kDifAlertHandlerClassStatePhase1, + }}; + + // set the alert we care about to class A + CHECK_DIF_OK(dif_alert_handler_configure_alert( + &alert_handler, kTopEarlgreyAlertIdRvCoreIbexRecovSwErr, + kDifAlertHandlerClassA, /*enabled=*/kDifToggleEnabled, + /*locked=*/kDifToggleEnabled)); + + // configure class A + CHECK_DIF_OK(dif_alert_handler_configure_class( + &alert_handler, kDifAlertHandlerClassA, configProfiles[0], + /*enabled=*/kDifToggleEnabled, + /*locked=*/kDifToggleEnabled)); +} + +/** + * - Verify the first escalation results in NMI interrupt serviced by the CPU. + * - Verify the second results in device being put in escalate state, via the LC + * JTAG TAP. + * - Verify the third results in chip reset. + * - Ensure that all escalation handshakes complete without errors. + * + * The first escalation is checked via the entry of the NMI handler and polling + * by dv. The second escalation is directly checked by dv. The third escalation + * is checked via reset reason. + */ +bool test_main(void) { + init_peripheral_handles(); // Check if there was a HW reset caused by the escalation. dif_rstmgr_reset_info_bitfield_t rst_info; @@ -121,17 +163,7 @@ bool test_main(void) { rstmgr_testutils_reason_clear(); if (rst_info & kDifRstmgrResetInfoPor) { - // set the alert we care about to class A - CHECK_DIF_OK(dif_alert_handler_configure_alert( - &alert_handler, kTopEarlgreyAlertIdRvCoreIbexRecovSwErr, - kDifAlertHandlerClassA, /*enabled=*/kDifToggleEnabled, - /*locked=*/kDifToggleEnabled)); - - // configurate class A - CHECK_DIF_OK(dif_alert_handler_configure_class( - &alert_handler, kDifAlertHandlerClassA, kConfigProfiles[0], - /*enabled=*/kDifToggleEnabled, - /*locked=*/kDifToggleEnabled)); + config_alert_handler(); // Initialize keymgr with otp contents CHECK_STATUS_OK(keymgr_testutils_advance_state(&keymgr, NULL)); @@ -151,12 +183,10 @@ bool test_main(void) { wait_for_interrupt(); LOG_ERROR("Should have reset before this line"); return false; - } else if (rst_info & kDifRstmgrResetInfoEscalation) { // DO NOT REMOVE, DV sync message LOG_INFO("Reset due to alert escalation"); return true; - } else { LOG_ERROR("Unexpected reset info %d", rst_info); } diff --git a/sw/device/tests/sim_dv/BUILD b/sw/device/tests/sim_dv/BUILD index c1a2004d8ce3b..e007bcbfac9f7 100644 --- a/sw/device/tests/sim_dv/BUILD +++ b/sw/device/tests/sim_dv/BUILD @@ -649,31 +649,6 @@ opentitan_test( ], ) -opentitan_test( - name = "alert_handler_escalation_test", - srcs = ["alert_handler_escalation.c"], - exec_env = {"//hw/top_earlgrey:sim_dv": None}, - deps = [ - "//hw/top_earlgrey:alert_handler_c_regs", - "//hw/top_earlgrey/sw/autogen:top_earlgrey", - "//sw/device/lib/arch:device", - "//sw/device/lib/base:memory", - "//sw/device/lib/base:mmio", - "//sw/device/lib/dif:alert_handler", - "//sw/device/lib/dif:clkmgr", - "//sw/device/lib/dif:keymgr", - "//sw/device/lib/dif:rstmgr", - "//sw/device/lib/dif:rv_core_ibex", - "//sw/device/lib/runtime:hart", - "//sw/device/lib/runtime:ibex", - "//sw/device/lib/runtime:log", - "//sw/device/lib/testing:alert_handler_testutils", - "//sw/device/lib/testing:keymgr_testutils", - "//sw/device/lib/testing:rstmgr_testutils", - "//sw/device/lib/testing/test_framework:ottf_main", - ], -) - opentitan_test( name = "alert_handler_entropy_test", srcs = ["alert_handler_entropy_test.c"],